考虑以下示例:
#include <iostream>
int main()
{
struct A {};
struct B : A {};
struct C : A, B {};
std::cout << sizeof(A) << '\n'; // 1
std::cout << sizeof(B) << '\n'; // 1
std::cout << sizeof(C) << '\n'; // 2, because of a duplicate base
struct E : A {virtual ~E() {}};
struct F : A, B {virtual ~F() {}};
std::cout << sizeof(E) << '\n'; // 8, the base overlaps the vtable pointer
std::cout << sizeof(F) << '\n'; // 16, but why?
}
在这里,您可以看到,struct E空的基类(大1个字节)使用了与vtable指针相同的存储空间,这与预期的一样。
但对于struct F具有重复的空基数的,则不会发生这种情况。是什么原因造成的?
我在GCC,Clang和MSVC上得到了相同的结果。上面的结果适用于x64,因此sizeof(void *) == 8。
有趣的是,对于struct G : A, B {void *ptr;};GCC和Clang,请执行EBO(大小为8),但MSVC不执行(大小为16)。
我喜欢研究这个。感谢您的问题和链接。我不确定我是否有答案,所以只评论一下。难道这是由
—
安德鲁·法兰加
C和的推导引入的歧义引起的F?毕竟,2 * sizeof(void*) == 16正如您所说,在x86_64上。编译器无法完全优化(如Story Teller所说),因此也不能。
在gcc和clang上得到相同的结果是正常的,因为它们都遵循itanium ABI。如果是这种情况,我认为在定义ABI时,他们担心布局算法可能会变得过于昂贵,因此他们采取了一些捷径(也就是悲观化)。
—
Marc Glisse
@RianQuinn重复的碱基不会使结构无效。
—
HolyBlackCat
@RianQuinn通过不同的“路径”从同一个类多次继承在C ++中是完全有效的。如果要创建菱形结构,即仅一次拥有基类,则必须使用虚拟继承。但是,如果您不想要钻石,并且拥有重复的基类对您来说不成问题,那么对于该语言而言也就不成问题。OP的代码仅产生警告,表示无法访问
—
sebrockm
A通过继承的第二个B。那样就好。仅当您确实尝试访问它时(如您的示例),您才会收到错误。
C(继承自A,B),您得到的结果A与B直接继承形式的结果有所不同