虚拟继承情况下类的大小

Size of the classes in case of virtual inheritance

本文关键字:继承 情况下 虚拟      更新时间:2023-10-16

有人可以解释一下在涉及虚函数的虚拟继承的情况下类的大小吗?

   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 version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

尺寸(A(: 8

数组中 3 个字节,1 个字节

填充,4 个字节用于 VPTR(指向 vtable 的指针(

尺寸(B(: 12

子对象:8,额外数组为 3 个字节,1 个字节填充

尺寸(C(: 16

这对你来说可能是令人惊讶的...子对象:8,3 字节用于额外数组,1 字节填充,4 字节指针指向 A

每当具有虚拟继承时,虚拟基子对象相对于完整类型开头的位置都是未知的,因此会向原始对象添加一个额外的指针来跟踪虚拟基的位置。请考虑以下示例:

struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};

当完整类型为B时,A相对于B对象的开头的位置可以不同于BA子对象在D的最终对象中的位置。如果这不明显,假设相对位置相同,并检查A相对于C的相对位置是否也可以保持C最终对象或D中的C子对象。

至于最后一个例子,我不太想分析它......但您可以阅读 Itanium C++ ABI,了解C++对象模型的具体实现。所有其他实现没有太大区别。


最后一个例子:

尺寸(D(: 32

D 包含一个 B 子对象 (12( 和一个 C 子对象 (16(,以及一个大小为 3 的附加数组和一个额外的填充位 1。

在这种特殊情况下,可能出现的问题是,如果C虚拟地继承自A,为什么有两个A子对象,答案是虚拟基础意味着对象愿意与层次结构中也愿意共享它的任何其他类型共享此基础。但在这种情况下,B不愿意共享它A子对象,所以C需要它自己的。

您应该能够通过将日志添加到不同级别的构造函数来跟踪这一点。在A的情况下,让它在编译器中获取一个值,并从每个扩展类传递不同的值。

sizeof(C)不仅仅是

sizeof(B),因为类型为C的对象(因为它实际上是从A继承的(将包含一个指针(除了vptr,B类型的对象也将包含(指向它从A继承的自身部分。 "了解虚拟函数、多重继承、虚拟基类和 RTTI 的成本",他的书《更有效C++

要知道数据结构的实际大小,你可以说编译者不要使用 pack(1( 在内存中对齐它 #pragma。要保存当前的打包设置并在以后恢复它们,您还可以使用 #pragma 包(推送(和 #pragma 包(流行(。

这是我对所有字节使用位置的最佳猜测:

              Avptr Bvptr CVptr DVptr k j i h k' j' i'  TOTAL
============= ========================================= =====
sizeof(A): 8    4                     4                   8
sizeof(B): 12        4                4 4                12
sizeof(C): 16              4          4 4 4              16
sizeof(D): 32                    4    4 4 4 4  4  4  4   32

哪里:

  • VPTR 每个占用 4 个字节(64 位指针(
  • char 数组每个占用 4 个字节(向上舍入以对齐(
  • k'、j' 和 i' 是通过 C 而不是 B 继承的那些变量的副本。