对C++中含有虚基类对象模型的思考

本文深入探讨了C++中虚基类与sizeof运算符的内存分配机制,通过实例分析了类大小计算与编译器类型的关系,揭示了内存分配的奥秘。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


今天看到一篇文章,上面提到了一个很有意思的问题,拿来跟大家分享一下

开门见山,下面是几个class的定义

class A

{

};

class B:virtual public A

{

};

class C:virtual public A

{

};

class D:public B, public C

{

};

int main()

{

 cout<<sizeof(A)<<endl<<sizeof(B)<<endl<<sizeof(C)<<endl<<sizeof(D)<<endl;

 system("pause");

 return 0;

}

请问程序的输出是什么?

感兴趣的可以自己试一下,我在这里直接贴出结果,我在GCC下编译得出的结果分别是:

1

8

8

16

在微软的visual studio 2010上编译得出的结果是:

1

4

4

8

程序的结果跟编译器有关系,说不定你用的另一版本的编译器得到的结果跟上面的两种都不同.

下面来分析一下这两种情况下的结果,如果有什么不对的地方请批评指正

先来看下第一个sizeof(A),两种情况都是1个字节,A是个空的class,为什么空的class还占一个字节,这不是在浪费memory?其实不然, 我们知道一个类的多个实例或者说对象都要占有一定的内存空间,这是实例化时调用构造函数后分配的, 如果A的实例不占有内存空间,也就是sizeof(A) 等于0,那么各个对象在内存中怎么区分呢,操作系统凭什么定位到各个对象呢?基于此原因, 编译器为每个空类的对象分配一个字节,这样使得浪费最少。扩展一下,如果A像下面这样定义

class A

{

  Int a;

};

那么sizeof(A)是不是就等于一个int的大小(32位系统下是4个字节)再加上A为空时的一个字节,得到的结果为4+1=5,如果考虑aliment的话结果为8呢?非也,既然A已经有一个Nonstatic data member,在内存中就要占用一定的内存,那么编译器就不用再自作多情分配一个字节给A来加以区分。

下面看下第二行的输出,两种编译器得到的结果不一样,一个sizeofB)为8一个sizeofB)为4,事实上,BC的大小主要受下面几个因素的影响:

1.  语言本身为了支持vitual base class而带来的额外的负担,我们很熟悉在C++中,为了支持虚函数等,产生了vptr vtbl等额外的负担,这里也一样,在BC中这种负担反应在一个指针上,这个指针可能指向A的子对象,也可能指向一个表格,这个表格包含了A的子对象的地址或者其偏移量。

2.  编译器对于特殊情况所提供的优化处理, 这里A1字节大小也出现在其子类BC身上,一般这一个字节会放在BC对象的尾部.但是某些编译器会对空的虚基类提供特殊的支持,这个特殊的支持的具体做法就是将一个空的虚基类看做是其子类对象的最开始的一部分,也就是说它并没有花费额外的空间,换句话说就是BC的对象里没有A的那1个字节的开销,那么在这里BC的大小就变成4个字节,这四个字节大小就是那个指向虚基类的指针.根据上面的输出,很显然,微软的visual studio 2010提供了对空的虚基类的特殊支持,gcc没有,所以gcc的输出BC的大小为

指针的大小+A1字节+字节对齐=8个字节

下面是gcc编译器中这几个类的结构:

Class Bclass C对象的结构

4个字节 指向class A的指针

Class A中的一个字节

 为了字节对齐填充的3个字节

              




                                                 class A(一个字节)


                             

下面是微软的编译器中这几个类的结构:

Class Bclass C对象的结构

4个字节 指向class A的指针

          

Class Bclass C已经分析完了,下面来看看class D的结构又是如何?

Class D派生自 BC,BC的大小跟编译器有关系,那么class D必然跟编译器的种类也存在着关系,似乎是废话,^_^.这里分析方法跟上面的class Bclass c一样,要看编译器对空的虚基类是否做了特殊处理



参考资料:《深度探索c++对象模型》


阅读(542) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值