虚拟继承中大多数派生类的大小

时间:2019-10-03 10:49:02

标签: c++ multiple-inheritance sizeof virtual-inheritance memory-layout

在下面的代码中,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
{
};

2 个答案:

答案 0 :(得分:2)

  

我认为,因为我们有虚拟基类,所以应该只有A的一个实例。

是的。

  

在下面的代码中,为什么D的大小是16个而不是8个字节?

在我的系统上,D是24个字节。

D包含一个B子对象(不包括A),一个C子对象(不包括A)和一个虚拟A子对象。

由于碱基不是标准布局,因此不需要空的碱基优化,并且每个碱基都有唯一的地址,因此尽管没有子对象本身也占用了内存。

此外(取决于编译器如何实现虚拟基础),虚拟继承需要使用虚拟表访问虚拟基础,因此实例将具有指向该表的虚拟指针。

答案 1 :(得分:2)

  

在下面的代码中,为什么D的大小是16个而不是8个字节?

在任何情况下,所有这些派生类都不能(实际上(*))具有与其虚拟基数A相同的大小:

  • 派生类对象与 non 虚拟直接基础子对象的关系就像与成员子对象的关系一样,是一对一关系;
  • 派生类对象与虚拟基础子对象的关系是多对一关系:根据定义,特定的虚拟基础子对象可以是多个派生类的 direct 基础。这里的A基础子对象是B对象(或另一个派生对象的子对象)的CD子对象的直接基础。

(*)我知道有可能违反该断言的实现方法,但是它们效率低下,笨拙且难以保证线程安全,甚至在线程化程序中效率也较低。

由于关系是一对多的,因此无法固定类布局(与非虚拟成员或成员不同)。唯一基础子对象的位置取决于所创建的确切派生类。

X的(g)左值表示类型X的实例或派生自X的类;因此,当使用不引用已知对象的(g)lvalue时(使用本地声明对象的名称时,根据定义的类型是已知的),基础子对象的地址在运行时根据类型(或地址)确定)嵌入在实例中的信息。

因此,BC需要携带此类信息来定位虚拟基础。这使它们比其基础大。最派生的类需要所有非虚拟基础中的位置信息空间,再加上虚拟基础本身(通常在有任何数据成员的情况下通常放置在末尾)。