【读书笔记】深度探索C++对象模型(更新中
2015-07-25 18:27
411 查看
第三章 Data 语义学
先看栗子
下面通过几个例子大概展示了C++对象内存布局在复杂的继承关系中使用的策略。开始之前,先来读读下面这段话
C++ Standard 并不强制规定如 “base class subobjects 的排列次序” 或 “不同存取层级的 data
member 的排列次序”这种琐碎细节。它也不规定 virtual functions 或 virtual base classes
的实现细节。C++ Standard 只是说:那些细节由各家厂商自定。
很坑爹吧? >_<
也因此, 代码运行得到的具体数值与系统环境和编译器有关,这对探讨没有影响。
LZ使用mingw-gcc
// ===== 弱爆了的分界线 =====//
先来看第一个case
// case 1 class X {}; class Y: public virtual X {}; class Z: public virtual X {}; class A: public Y, public Z {}; // sizeof X Y Z A -> 1 4 4 8
对于一个空的对象,编译器会为它至少分配一个byte。所以 sizeof(X) = 1。
虚继承 会造成相应的负担,在 derived class 中,这种负担反应在某种形式的指针上。
gcc 的实现上,指针是指向虚表的。
指针是4字节的,所以 Y, Z 的 size 至少是4字节。
聪明的读者一定会问,继承来的基类子对象不是还有一个 byte 吗?
事实的确如此, 在一些机器上,sizeof(Y) = 4(vptr) + 1(base subobject) + 3(alignment) = 8 byte
而像 gcc 这样的编译器, 为 empty virtual base class 提供特殊优化。
在这个策略下,一个 empty virtual base class 被视为 derived class object 最开头的一部分,
也就是说它并没有花费任何的空间, 这就节省了上面所说的编译器所插入的 1 byte。
所以 Y, Z 只包含一个 vptr,size 就是 4 byte。
确定 A 的 size 时需要先解决一个问题,X 在 A 中有几个副本(尽管这里可以优化)?
答案是, 只有 1 个
一个 virtual base class subobject 只会 derived class 中存在一份实体, 不管它在继承体系中出现多少次!
所以 sizeof(A) 的计算方式:
- 共享的唯一的 X 实体,优化后为 0
- base class Y 的大小, 减去因 X 而配置的大小。base class Z 同。4 - 0 + 4 - 0 = 8
- class A 自己的大小: 0
- class A 的对齐: 0
则 sizeof(A) = 8
case 2 和 case 3 的计算方式相同, 作为 excercise 吧。
// case 2 // 与 case 1 唯一的区别是 X 有了一个 char 类型的 data member class X {char data;}; class Y: public virtual X {}; class Z: public virtual X {}; class A: public Y, public Z {}; // sizeof X Y Z A -> 1 8 8 12
// case 3 class X {int data;}; class Y: public virtual X {}; class Z: public virtual X {}; class A: public Y, public Z {}; // sizeof X Y Z A -> 1 8 8 12
对于 case 4, 并没有用到虚继承,所以也不会有相应的负担。
这种情况,可以简单理解为在 derived class 中直接放入 base class。
// case 4 class X {char data;}; class Y: public X {}; class Z: public X {}; class A: public Y, public Z {}; // sizeof X Y Z A -> 1 1 1 2
Further reading:
C++ 多继承和虚继承的内存布局 详细解释了由gcc编译器实现多继承和虚继承的对象的布局
相关文章推荐
- C/C++求职宝典21个重点笔记(常考笔试面试点)
- c++ primer 学习笔记-第一章
- C++ 继承与接口 知识点 小结(一)
- c++builder 代码输入助手
- C语言,变量与内存
- POJ1988基本的并查集
- C++入门经典 笔记(第四章)使用表达式、语句和运算符
- c语言中阶乘的精确值
- C语言结构体(struct)常见使用方法 blog.csdn.net/huqinwei987/article/details/23625823
- C++ 深入理解 虚继承、多重继承和直接继承
- C语言,数据类型
- (C++)String的用法
- getcher getch getched用法和缓冲区的概念
- ios入门之c语言篇——基本函数——3——判断日期是一年的第几天
- ios入门之c语言篇——基本函数——2——判断闰年
- ios入门之c语言篇——基本函数——1——随机数生成
- c++数组声明但不初始化,系统如何赋值
- C++栈的顺序存储和链式存储的实现
- (C++)STL排序函数sort和qsort的用法与区别
- XCode创建C++工程