谁能解释一下在涉及虚函数的虚继承的情况下类的大小。
class A{
char k[ 3 ];
public:
virtual void a(){};
};
class B : public A{
char j[ 3 ];
public:
virtual void b(){};
};
class C : public virtual A{
char i[ 3 ];
public:
virtual void c(){};
};
class D : public B, public C{
char h[ 3 ];
public:
virtual void d(){};
};
类大小的输出是:
sizeof(A): 8
sizeof(B): 12
sizeof(C): 16
sizeof(D): 32
我使用的编译器是
gcc 版本 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)
最佳答案
sizeof(A): 8
数组中的 3 个字节,1 个字节的填充,4 个字节的 vptr(指向 vtable 的指针)
sizeof(B): 12
一个子对象:8个,3个字节用于额外数组,1个字节填充
sizeof(C): 16
这可能是让您感到惊讶的... A 子对象:8 个,3 个字节用于额外数组,1 个字节填充,4 个字节指向 A
只要你有虚拟继承,虚拟基子对象相对于完整类型开始的位置是未知的,所以一个额外的指针被添加到原始对象以跟踪虚拟基的位置。考虑这个例子:
struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};
当完整类型为 B
时,A
相对于 B
对象的位置可以不同于该位置B
的 A
子对象,当它是最终对象 D
的一部分时。如果这不明显,假设相对位置相同,并检查 A
相对于 C
的相对位置是否在 C
也可以维护 D
中的最终对象或 C
子对象。
至于最后一个例子,我不太想分析它......但你可以阅读 Itanium C++ ABI用于 C++ 对象模型的具体实现。所有其他实现都没有太大区别。
最后一个例子:
sizeof(D): 32
D 包含一个 B 子对象 (12) 和一个 C 子对象 (16),以及一个大小为 3 的附加数组和一个额外的填充位 1。
在这种特殊情况下,可能出现的问题是,如果 C
实际上继承自 A
,为什么会有两个 A
子对象,并且答案是虚拟基意味着对象愿意与层次结构中也愿意共享它的任何其他类型共享这个基。但是在这种情况下 B
不愿意共享它的 A
子对象,所以 C
需要它自己的。
您应该能够通过向不同级别的构造函数添加日志来跟踪这一点。在 A
的情况下,让它在编译器中获取一个值,并从每个扩展类传递不同的值。
关于c++ - 虚拟继承情况下类的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10541149/