C++ 虚拟继承情况下类的大小

C++ 虚拟继承情况下类的大小,c++,polymorphism,virtual,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 : p

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

   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(C)
sizeof(B)
更重要,因为C类型的对象(因为它实际上从A继承)将包含指针(除了vptr之外,B类型的对象也将包含)Scott Meyers在其书的第24项“了解虚拟函数、多重继承、虚拟基类和RTTI的成本”中详细解释了它从A.Scott Meyers继承的部分(约10页)

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

              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位指针)
  • 字符数组每个占用4个字节(为了对齐而向上舍入)
  • k',j'和i'是通过C而不是B继承的变量的副本

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

规模(A):8

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

规模(B):12

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

sizeof(C):16

这对你来说可能是个惊喜。。。 子对象:8,3字节用于额外数组,1字节填充,4字节指针指向

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

struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};
当完整类型为A
B
时,
A
相对于
B
对象开始的位置可以不同于
B
A
子对象作为最终对象
D
的一部分时的位置。如果这不明显,则假设相对位置相同,并检查
C
最终对象中
A
相对于
C
的相对位置或
D
中的
C
子对象的相对位置是否也可以维护

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


最后一个例子:

尺寸(D):32

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

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


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

将vptr的大小添加到类的大小中。有关详细信息->这些尺寸有什么让您感到惊讶?请记住,所有非空的基子对象都必须正确对齐。因此,如果你愿意,你可以考虑每个类都有一个4字节的4位成员对齐。@ FrdelsLon……我知道多态性类受虚拟指针影响的大小。但是实际上继承的效果是什么?当我们实际上继承时,有没有隐藏的指针???@DumbCoder:没那么简单。虚拟表需要A
vptr
,但您需要虚拟基的额外指针。C不扩展B,因此它不包含j。额外的4个是指向子对象的指针