c++中包含empty virtual base class 类的sizeof结果分析

来源:互联网 发布:我的心情无人知 编辑:程序博客网 时间:2024/05/17 08:34

背景

类的继承关系如下
class Base{};class First:public virtual Base{};class Second:public virtual Base{};class Top:public First,public Second{};
考虑如下运算的结果
sizeof Basicsizeof Firstsizeof Secondsizeof Top

答案

有两个版本的结果
版本1
sizeof Basic = 1sizeof First = 8sizeof Second = 8sizeof Top = 12

版本2(编译器优化版本)
sizeof Basic = 1sizeof First = 4sizeof Second = 4sizeof Top = 8

解析

版本1

Basic大小为1:

编译器为了让Base这一空虚基类的每一个实例拥有不同的内存地址,也就是说为了区分Base的不同实例,向其中添加了一个影藏的char。
Base a,b;if(&a != &b)   //这一句就是添加char的动机{    std::cout<<"a和b当然不是同一个实例";}

First和second的大小为8:
这个就有趣了。
首先,毫无疑问子类中有基类的1个字节
其次,由于该类含有虚基类,所以编译器给它安插了一个指针(我们暂且叫做vptr),用来指向虚机类的地址(或者偏移量),指针在32位的应用中为4字节
最后,还有3字节是啥?这3字节用来内存对齐(alignment)。为了附和某些底层机制,数据结构最好为4的整数倍大小,这样程序的运行会得到最高的效率,所以这儿补充了   额外的3字节空内容。

这里有个问题:为啥First和Second也为空的类,就不用添加那一个char呢?我是这么理解的:对于编译器来说,First和Second中有一个vptr所以编译器不认为这两个类是空的,自然不用添加那一个char


Top的大小为12:
先明确虚基类的意义:虚基类确保继承链中只有该虚基类的一个唯一实例。也就是说Top中不会因为First和Second的两个分支而带来两个Base基类成分,所有分支共享一个Base实例。好,我们来算大小。
首先,唯一一个来自虚基类的成分,大小为1字节。
其次,First和Second中除去虚基类的成分各有4个字节。
最后,这时大小为9,补位又来了,补到12字节。

版本2

版本2源于编译器对empty virtual base class 的优化,摘抄一段《inside the c++ object model》的原文
Under this strategy, an empty virtual base class is treated as being coincident with the beginning of the derived class object; that is, it takes up no additional space. 
这段话有点拗口,我是这么理解的:将虚基类”融合“进子类中,成为子类开头的一部分,之后为了标识这是一个继承了虚基类的类,则还得保留那个vptr,指向自己的开头。
所以我们再来看大小:
Base: 1字节,解释同上
First和Second:只有一个vptr一共4字节,此时不用补位
Top:包括First和Second,各4字节,Base已经融合到了First和Second中,不用再加,此时Top为8字节,不用补位。所以一共8字节。


后话

c++中有很多看似无法理解甚至看起来有点“脑残”的现象和规定。其实他们的出现都是有原因的,或是兼容性问题,或是语言实现本身的要求,亦或根本就是弄混了c++不同分支的规定,张冠李戴。但只要弄清这些由来,这些“脑残”的东西也就成了自然。一切都逃不过追本溯源!




0 0
原创粉丝点击