在下面的代码中,D
的大小为什么是16
而不是8
个字节?
我想是因为我们有虚拟基类,所以应该只有A
的一个实例。
class A
{
public:
int x_;
int y_;
};
class B : virtual public A
{
};
class C : virtual public A
{
};
class D : public B, public C
{
};
答案 0 :(得分:2)
我认为,因为我们有虚拟基类,所以应该只有A的一个实例。
是的。
在下面的代码中,为什么D的大小是16个而不是8个字节?
在我的系统上,D是24个字节。
D包含一个B子对象(不包括A),一个C子对象(不包括A)和一个虚拟A子对象。
由于碱基不是标准布局,因此不需要空的碱基优化,并且每个碱基都有唯一的地址,因此尽管没有子对象本身也占用了内存。
此外(取决于编译器如何实现虚拟基础),虚拟继承需要使用虚拟表访问虚拟基础,因此实例将具有指向该表的虚拟指针。
答案 1 :(得分:2)
在下面的代码中,为什么D的大小是16个而不是8个字节?
在任何情况下,所有这些派生类都不能(实际上(*))具有与其虚拟基数A
相同的大小:
A
基础子对象是B
对象(或另一个派生对象的子对象)的C
和D
子对象的直接基础。(*)我知道有可能违反该断言的实现方法,但是它们效率低下,笨拙且难以保证线程安全,甚至在线程化程序中效率也较低。
由于关系是一对多的,因此无法固定类布局(与非虚拟成员或成员不同)。唯一基础子对象的位置取决于所创建的确切派生类。
类X
的(g)左值表示类型X
的实例或派生自X
的类;因此,当使用不引用已知对象的(g)lvalue时(使用本地声明对象的名称时,根据定义的类型是已知的),基础子对象的地址在运行时根据类型(或地址)确定)嵌入在实例中的信息。
因此,B
和C
需要携带此类信息来定位虚拟基础。这使它们比其基础大。最派生的类需要所有非虚拟基础中的位置信息空间,再加上虚拟基础本身(通常在有任何数据成员的情况下通常放置在末尾)。