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.单一的虚拟继承:有成员变量 ...
随机推荐
- IP组播 MulticastChannel接口 DatagramChannel实现
监听者 import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; impo ...
- 我的职业规划(android)
通过一段时间的想法,自己大概圈定了自己的未来三年的职业规划,关于android的,希望大家多多批评,多多指教.或者大家也能讨论下自己对于未来的期许或者路线,虽然每个人都有自己自身的情况,但是总会有一些 ...
- 用GO写一个连接比特币JSONRPC接口的程序
比特币钱包默认是不开启JSONRPC接口的,要在比特币区块文件夹下新建bitcoin.conf这个文件,并写入以下内容 server=1 rpcuser=xxmm rpcpassword=1234 ...
- js判断两个日期是否相等的方法
今天优化代码的时候,发现一个问题,js比较日期是否相等时,我用==去比较,发现两个时间不相等但是运行结果却是true,然后去百度了下发现oldStartTime, startTime都是对象,类型为引 ...
- 【win7下安装node.js错误:roling back action】与【"grunt" 不是内部或外部命令】 解决方法
[win7下安装node.js错误:roling back action] 解决方法: Node.js 服务器端的JavaScript Node.js 是一个基于Chrome JavaScript 运 ...
- Linux入门进阶第四天——服务管理
以下均基于CentOS6.3,其中有部分命令已经过时,在CentOS7中不再使用,请注意 [更新]:CentOS7改变: CentOS .0中一个最主要的改变,就是切换到了systemd.它用于替代红 ...
- 【HDU3117】Fibonacci Numbers
[HDU3117]Fibonacci Numbers 题面 求斐波那契数列的第\(n\)项的前四位及后四位. 其中\(0\leq n<2^{32}\) 题解 前置知识:线性常系数齐次递推 其实后 ...
- Linux安装gitlab
一.GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务.安装方法是参考GitLab在GitHub上的Wiki页面. 二.我相信使用过git的开 ...
- Drupal7 配置多站点及为每个站点设置语言
默认情况 在Drupal7的安装目录下存在sites目录 sites目录结构如下: --all --default --example.sites.php --README.txt 1. 添加新域名, ...
- WPF RegisterAttached ListBoxItem(附加属性传递到Item)
/// <summary> /// Controls的附加属性 /// </summary> public class ControlsAttached : Dependenc ...