虚拟继承时类的大小

时间:2012-05-10 19:49:38

标签: c++ polymorphism virtual

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

   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)

4 个答案:

答案 0 :(得分:7)

  

sizeof(A):8

数组中的3个字节,1个字节的填充,4个字节的vptr(指向vtable的指针)

  

sizeof(B):12

子对象:8,3个字节用于额外阵列,1个字节填充

  

sizeof(C):16

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

每当您具有虚拟继承时,虚拟基础子对象相对于完整类型的开头的位置是未知的,因此将额外的指针添加到原始对象以跟踪虚拟基础的位置。考虑这个例子:

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

当完整类型为A时,B相对于B对象开头的位置可能与A子对象的位置不同B当它是最终对象D的一部分时。如果这不明显,请假设相对位置相同,并检查A最终对象中C相对于C的相对位置或{{1} <{1}}中的子对象也可以维护。

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


最后一个例子:

  

sizeof(D):32

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

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

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

答案 1 :(得分:1)

sizeof(C)超过sizeof(B),因为C类型的对象(因为它实际上是从A继承)将包含一个指针(除了类型B的对象也将包含的vptr)指向对于自己继承自A. Scott Meyers本身的部分,在第24项中详细解释了这一点(大约10页):'了解他的书中的虚函数,多继承,虚基类和RTTI的成本'{{ 3}}

答案 2 :(得分:0)

要知道数据结构的实际大小,您可以说编译器不使用#pragma pack(1)将其与内存对齐。要保存当前的打包设置并在以后恢复它们,您还可以使用#pragma pack(push)和#pragma pack(pop)。

答案 3 :(得分:-1)

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

              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

其中:

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