5

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

   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

4 回答 4

7

大小(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 {};

当完整类型为 a 时A,相对于对象开始的位置可以不同于当它是最终对象的一部分时的子对象的位置。如果这不明显,则假设相对位置相同,并检查相对于最终对象或子对象中的相对位置是否也可以保持。BBABDACCCD

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


最后一个例子:

大小(D):32

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

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

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

于 2012-05-10T20:31:06.523 回答
1

sizeof(C)不仅仅是sizeof(B)因为 C 类型的对象(因为它实际上是从 A 继承的)将包含一个指针(除了 B 类型的对象也将包含的 vptr 之外)指向它从 A 继承的自身部分。Scott Meyers在他的书更有效的 C++的第 24 项中详细解释了这一点(大约 10 页):“了解虚函数、多重继承、虚拟基类和 RTTI 的成本”

于 2012-05-10T20:10:36.433 回答
0

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

于 2012-05-10T20:23:52.810 回答
-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

在哪里:

  • vptr 每个占用 4 个字节(64 位指针)
  • char 数组每个占用 4 个字节(四舍五入以对齐)
  • k'、j' 和 i' 是通过 C 而不是 B 继承的那些变量的副本。
于 2012-05-10T20:15:44.967 回答