虚拟继承下空类型的sizeof问题

前面提到过一般空类型的sizeof问题,见链接:
http://blog.csdn.net/capecape/article/details/77702446
经过进一步学习,发现虚拟继承和多重继承下空类型的sizeof的计算更有意思。以下是对《Inside C++ Object Model》中第三章的总结。

以下是基类和子类的继承关系代码:

class X {};
class Y:virtual public X {};
class Z:virtual public X{};
class A:public Y,public Z{};

X,Y,Z,A的继承关系图为:
X,Y,Z,A的继承关系图
对X,Y,Z,A求sizeof与机器有关,也与编译器有关。

1)对于一些老式机器的编译器

  • X为基类(base class)的空类型

    内部无任何明显数据,sizeof本来应该是0,但一个类或该类对象必须占有一定的空间(这样每个该类对象才能有唯一地址),该空间默认为1。

  • Y,Z为X的派生类(derived class)的空类型

    它们的内存空间包括3个部分:
    1)指向虚基类的指针,占4bytes
    2)本身空的,0字节;继承X的一字节,占1byte
    3)调整总大小为4bytes的倍数,故调整填充占3字节

    X,Y,Z的对象布局

    故Y,Z的sizeof都为8。

  • A多重继承自Y,Z
    它的内存空间包括4个部分:
    1)基类Y的大小(减去因虚基类X而配置的大小),占4bytes,基类Z的大小同理
    2)本身空的,0字节;继承共享的唯一一个X实体,1byte
    3)调整总大小为4bytes的倍数,故调整填充占3字节

    X,Y,Z,A的对象布局

故A的sizeof为12字节。

2)对于新近的大多数编译器(例如:Visual C++)

在现在的新编译器下,一个空的虚基类被视为派生类最开头的部分,也就是说没有花费任何额外空间,这就节省了一般机器的char onebyte。也就不需要调整填充了(alignment padding)。在此模型下,Y和Z的大小都是4而不是8。

同样,A也只继承Y,Z的指针部分,不需要继承自X的1字节实体,也不需要填充。故为8bytes。

Visual C++ X,Y,X,Z的对象模型

总结:

  1. 虚拟继承,会生成一个指针(4字节)指向虚拟基类。
  2. 对于老式机器(编译器),子类会继承基类的(char onebyte)
  3. 对于新兴编译器,子类不会继承基类的onebyte。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于C++继承问题,我会尽力回答。以下是代码和注释: ```cpp #include <iostream> using namespace std; // 不带虚拟继承的父类 class A { public: int a; }; // 不带虚拟继承的子类1 class B1 : public A { public: int b1; }; // 不带虚拟继承的子类2 class B2 : public A { public: int b2; }; // 不带虚拟继承的菱形继承 class C : public B1, public B2 { public: int c; }; // 带虚拟继承的父类 class VA { public: int va; }; // 带虚拟继承的子类1 class VB1 : virtual public VA { public: int vb1; }; // 带虚拟继承的子类2 class VB2 : virtual public VA { public: int vb2; }; // 带虚拟继承的菱形继承 class VC : public VB1, public VB2 { public: int vc; }; // 主函数 int main() { cout << "sizeof(int): " << sizeof(int) << endl; // 输出int类型的内存大小 cout << "sizeof(A): " << sizeof(A) << endl; // 输出不带虚拟继承的父类A的内存大小 cout << "sizeof(B1): " << sizeof(B1) << endl; // 输出不带虚拟继承的子类B1的内存大小 cout << "sizeof(B2): " << sizeof(B2) << endl; // 输出不带虚拟继承的子类B2的内存大小 cout << "sizeof(C): " << sizeof(C) << endl; // 输出不带虚拟继承的菱形继承类C的内存大小 cout << "sizeof(VA): " << sizeof(VA) << endl; // 输出带虚拟继承的父类VA的内存大小 cout << "sizeof(VB1): " << sizeof(VB1) << endl; // 输出带虚拟继承的子类VB1的内存大小 cout << "sizeof(VB2): " << sizeof(VB2) << endl; // 输出带虚拟继承的子类VB2的内存大小 cout << "sizeof(VC): " << sizeof(VC) << endl; // 输出带虚拟继承的菱形继承类VC的内存大小 return 0; } ``` 输出结果为: ``` sizeof(int): 4 sizeof(A): 4 sizeof(B1): 8 sizeof(B2): 8 sizeof(C): 16 sizeof(VA): 4 sizeof(VB1): 16 sizeof(VB2): 16 sizeof(VC): 24 ``` 可以看到,不带虚拟继承的菱形继承类C中,父类A的成员变量在子类B1和B2中都会出现一遍,因此C的内存大小为16个字节(8字节B1 + 8字节B2)。而带虚拟继承的菱形继承类VC中,父类VA的成员变量只会在子类VB1和VB2中出现一遍,因此VC的内存大小为24个字节(16字节VB1 + 16字节VB2 - 8字节VA)。虚拟继承可以避免菱形继承中的重复继承问题,但会增加一些额外的开销。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值