C++对象内存布局测试总结
C++对象内存布局测试总结
http://hi.baidu.com/����/blog/item/826d38ff13c32e3a5d6008e8.html
上文是半年前对虚函数、虚拟继承的理解。可能有一些错漏。而且只是理解了比较简单的部分,表达也不够清晰,这次决定花的时间再做一次总结。
对于普通的C++对象内存布局,简单得不得了,就不做总结了。这里只总结涉及到虚拟继承的情况。
因为不同编译器对虚拟继承的实现采用不同的方式,所以要完整的分析是不可能的。这里只考虑VS2005/2008,还有简单涉及GCC编译器。
1、 单个虚拟继承
只是为了分析而已,实际中并没有太大的作用。跟虚拟继承相关的派生类对象的内存布局跟具体的编译器相关。
(1)VS编译器:无论有无虚函数,必然含有虚基类表指针。虚基类表中的内容为本类实例的偏移和基类实例的相对偏移值。如果有虚函数,那么基类的虚函数表跟派生类的虚函数表是分开的。
在内存布局上,地址从低到高,顺序如下:派生类的虚函数表指针+虚基类表指针+派生类的成员变量+“间隔”(4个字节)+基类的虚函数表指针+基类的成员变量。派生类跟基类实例的位置关系跟普通继承正好相反。
说明:“间隔”产生的原因是派生类重写了基类的虚函数。如果没重写,则这一项没有。"本类地址"指的是包含有虚基类的对象(或部分对象),也就是继承链上 的直接子类对象的地址,本例比较简单,就是派生类对象地址。“本类地址跟虚基类表指针地址只差”,这个值经常是-4、0,-4表明“本类”还有一个虚函数 表指针;0则表明“本类”的第一个4字节保存的就是虚基类表指针,没有虚函数表指针。

图 1 VS编译器—单个虚拟继承
(2)GNU的GCC编译器:跟VS的编译器类似,有不同的地方是,虚基类表跟派生类的虚函数表合并。另外通过虚基类表指针往正负两个方向寻址,可以获得 不同偏移值,也就是说有两个功能一样的虚函数表。不过在实际应用的时候,不知道虚基类表是否真的有用,测试了简单的情况发现编译器做了优化,根本就没有用 虚基类表来寻址虚基类实例。

图 2 GCC编译器—单个虚拟继承
2、 虚拟继承多个基类
虚基类表要增加内容,有N个虚基类就有N项基类实例偏移值,再加上1项本类实例的偏移值,也就是N+1。
假设C虚拟继承了A类和B类,考虑最复杂的情况(都有虚函数),那么C类对象的内存布局如下
(VS编译器):
C类虚函数表指针+虚基类表指针+C类成员变量+A类间隔(4个字节) + A类虚函数表指针+ A类成员变量+ B类间隔(4个字节)+B类虚函数表指针+ B类成员变量。
说明:当派生类重写了该基类的虚函数,才会有“间隔”。“间隔”属于虚函数被重新实现了的虚基类,可能是一个标志,也有可能是在函数调用的时候用上。不是很清楚。

图 3 VS编译器—虚拟继承多个基类
(GCC编译器):
C类虚函数表指针(包含虚基类表) + C类成员变量 + A类虚函数表指针 + A类成员变量 + B类虚函数表指针 + B类成员变量。
相比较执行,使用GCC编译器,派生类对象小一些。(图略)
3、 虚拟继承之菱形继承
这里的菱形继承指的是:B、C虚拟继承A,然后D普通继承B、C。
D类的对象的内存布局如下
(VS编译器)
B类虚函数表指针(该虚函数表包含D类独有的虚函数的地址)+B类虚基类表指针+B类成员变量+C类虚函数表指针+C类虚基类表指针+C类成员变量+D类成员变量+“间隔”+A类虚函数表指针+A类成员变量。
说明:如果A类的虚函数没有被重写,那么就没有“间隔”。

图 4 VS编译器—菱形继承
(GCC编译器)
把B、C类的虚函数表跟虚基类表合并就是了。(图略)
4、VS编译器,“间隔”的疑问
“间隔”的问题,在没有虚函数的情况下,重写是没有“间隔”的,所以觉得可能跟虚函数有关,也就是说是为了实现多态,具体是用在哪个地方,做 了简单的反汇编调试(父类指针指向子类对象,调用被子类重写了的虚函数),并没有发现哪里用到了“间隔”,可能要在复杂的调用才会用上吧,目前搞不清楚。
5、虚基类表的问题
通过反汇编调试发现在使用多态的时候,VS编译器会去使用虚基类表,用于寻址虚基类地址。而GCC编译器则没有这么做,测试了比较简单的情况,发现它做了优化,并没有利用虚基类表,而是直接在派生类对象地址上加上一个常数,获得虚基类实例的地址。
学习参考:
http://blog.csdn.net/haoel/archive/2008/10/15/3081328.aspx
http://blog.csdn.net/BlueDog/archive/2009/10/22/4711169.aspx
《深度探索C++对象模型》也是非常好的资料,只是该书较旧,而类对象布局又是编译器的个性属性,手上的编译器有可能不是按照书里的来实现(譬如书中强调 虚函数表指针放在类对象的结尾,以便兼容C,而实际上编译器没有这么做,还有,数据成员的地址也没有像书中所说的那样),所以动手实践才有真理。
C++对象内存布局测试总结的更多相关文章
- 图说C++对象模型:对象内存布局详解
0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...
- c++ 对象内存布局详解
今天看了的,感觉需要了解对象内存的问题.参考:http://blog.jobbole.com/101583/ 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个 ...
- c++对象内存布局
这篇文章我要简单地讲解下c++对象的内存布局,虽然已经有很多很好的文章,不过通过实现发现有些地方不同的编译器还是会有差别的,希望和大家交流. 在没有用到虚函数的时候,C++的对象内存布局和c语言的st ...
- c++对象内存布局的理解
我对c++对象内存布局的理解 引言 结合网上的一些资料,通过自己的一番摸索,得出了一点个人见解.现在写下来,希望与各位同学共同探讨,共同进步. 以下所有代码均是在VS2012下测试. 一个普通的基 ...
- 好文章系列C/C++——图说C++对象模型:对象内存布局详解
注:收藏好文章,得出自己的笔记,以查漏补缺! ------>原文链接:http://blog.jobbole.com/101583/ 前言 本文可加深对C++对象的内存布局.虚表指针.虚 ...
- 使用sos查看.NET对象内存布局
前面我们图解了.NET里各种对象的内存布局,我们再来从调试器和clr源码的角度来看一下对象的内存布局.我写了一个测试程序来加深对.net对象内存布局的了解: using System; using S ...
- 【转载】图说C++对象模型:对象内存布局详解
原文: 图说C++对象模型:对象内存布局详解 正文 回到顶部 0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看.本文的结论都在 ...
- 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局
继承是C++作为OOD程序设计语言的三大特征(封装,继承,多态)之一,单一非多态继承是比较好理解的,本文主要讲解GCC环境下的多重继承和虚拟继承的对象内存布局. 一.多重继承 先看几个类的定义: 01 ...
- C++对象内存布局 (二)
在上一篇文章中讨论了C++单一一般继承的对象内存布局http://www.cnblogs.com/uangyy/p/4621561.html 接下来继续讨论第二种情况: 2.单一的虚拟继承:有成员变量 ...
随机推荐
- Hadoop(二)CentOS7.5搭建Hadoop2.7.6完全分布式集群
一 完全分布式集群(单点) Hadoop官方地址:http://hadoop.apache.org/ 1 准备3台客户机 1.1防火墙,静态IP,主机名 关闭防火墙,设置静态IP,主机名此处略,参考 ...
- 搭建最小linux系统
Busybox简介 • 制作文件系统我们需要使用到Busybox 工具 – 版本为busybox-1.21.1.tar.bz2 – 开源网址是http://www.busybox.net/ – Bus ...
- LFS搭建第一天
1. 前期准备 vmware 软件安装 LFS iso 下载:http://ftp.osuosl.org/pub/lfs-livecd/lfslivecd-x86-6.3-r2145.iso 2.新建 ...
- ubuntu18.04 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)解决方法
出现问题: 最近打开系统之后没声儿,抽空解决以下,谁知道安装的时候出现了这个问题,一看就是锁被占了呗 直接重启大法.....不行,看来是锁分配出问题了,找了个解锁命令 jiang@ryzen:~$ s ...
- BFC与浮动
一.BFC的含义 BFC(block formatting contexts) 块级元素格式化上下文,它决定了块级元素如何对它的内容进行布局,以及与其它元素的关系和相互作用. 块级元素:父级(是一个块 ...
- Python之路(四)--->list、元组、字典
好久没有更新了,感觉自己写的东西并没有太多人看,可能是因为写的不好,也可能是太基础了.学习是一个漫长的过程,结果结果固然重要,但是更重要的是在学习的过程中所学到方法,这些方法在以后的生活还是工作中都能 ...
- 20155239 2016-2017-2 《Java程序设计》第10周学习总(2017-04-22 16:26
教材学习 1.基本概念划分 OIS的七层协议: 应用层.表示层.会话层.运输层.网络层.数据链路层.物理层. OIS的五层协议: 应用层.运输层.网络层.数据链路层.物理层. 由下往上介绍如下: 2. ...
- 20155325 2016-2017-2 《Java程序设计》第1周学习总结
教材学习内容总结 三大平台 java SE:JVM(java虚拟机),JRE(运行java程序),JDK(包括JRE及开发过程中需要的一些工具程序),java语言. java EE:基于java SE ...
- 20155338 2016-2017-2《Java程序设计》实验四Android程序开发实验报告
2016-2017-2 20155338 <Java程序设计>实验四Android程序开发实验报告 实验过程及成果展示 1.修改res目录下的layout文件夹中的activity_mai ...
- 微信小程序判断按钮是否显示,或者隐藏
js中: onLoad:function(options) { this.setData({ orderstate:'待送检' }) }, WXML中: <view wx:if=" ...