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++对象内存布局测试总结的更多相关文章

  1. 图说C++对象模型:对象内存布局详解

    0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...

  2. c++ 对象内存布局详解

    今天看了的,感觉需要了解对象内存的问题.参考:http://blog.jobbole.com/101583/ 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个 ...

  3. c++对象内存布局

    这篇文章我要简单地讲解下c++对象的内存布局,虽然已经有很多很好的文章,不过通过实现发现有些地方不同的编译器还是会有差别的,希望和大家交流. 在没有用到虚函数的时候,C++的对象内存布局和c语言的st ...

  4. c++对象内存布局的理解

    我对c++对象内存布局的理解   引言 结合网上的一些资料,通过自己的一番摸索,得出了一点个人见解.现在写下来,希望与各位同学共同探讨,共同进步. 以下所有代码均是在VS2012下测试. 一个普通的基 ...

  5. 好文章系列C/C++——图说C++对象模型:对象内存布局详解

    注:收藏好文章,得出自己的笔记,以查漏补缺!     ------>原文链接:http://blog.jobbole.com/101583/ 前言 本文可加深对C++对象的内存布局.虚表指针.虚 ...

  6. 使用sos查看.NET对象内存布局

    前面我们图解了.NET里各种对象的内存布局,我们再来从调试器和clr源码的角度来看一下对象的内存布局.我写了一个测试程序来加深对.net对象内存布局的了解: using System; using S ...

  7. 【转载】图说C++对象模型:对象内存布局详解

    原文: 图说C++对象模型:对象内存布局详解 正文 回到顶部 0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看.本文的结论都在 ...

  8. 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局

    继承是C++作为OOD程序设计语言的三大特征(封装,继承,多态)之一,单一非多态继承是比较好理解的,本文主要讲解GCC环境下的多重继承和虚拟继承的对象内存布局. 一.多重继承 先看几个类的定义: 01 ...

  9. C++对象内存布局 (二)

    在上一篇文章中讨论了C++单一一般继承的对象内存布局http://www.cnblogs.com/uangyy/p/4621561.html 接下来继续讨论第二种情况: 2.单一的虚拟继承:有成员变量 ...

随机推荐

  1. [教学] Delphi IDE 文件搜寻功能

    Delphi IDE 提供了一个方便的文件搜寻功能,操作如下: 点 Search 选单内的 Find in Files... 例如我们想搜寻 JFile 需要引用那一个源码,可输入如下: 输入关键字: ...

  2. 在AI人工智能中如何巧妙学习大数据编程,成为五十万年薪的佼佼者

    编辑 ai狗年 大数据和人工智能的关系,首先要说什么是大数据.这些年来,大数据先是被神化,继而又被妖魔化,到了今天,其实谁也不知道别人所谓的大数据指的是什么.我大数据从业者,建了一个大数据资源共享群1 ...

  3. 树莓派3B+简单入门

    刚刚入手一个树莓派3B+,树莓派板子.3.5寸电阻触摸屏.16G内存卡.外壳电源等一系列配件一共花了360大洋,这东西真不便宜.这里介绍一下系统安装.3.5寸屏幕安装.VNC远程屏幕. 先给大家看一下 ...

  4. sqli-labs (less-8-less-10)

    盲注需要掌握一些MySQL的相关函数:length(str):返回str字符串的长度.substr(str, pos, len):将str从pos位置开始截取len长度的字符进行返回.注意这里的pos ...

  5. Go语言中的字符串处理

    1 概述 字符串,string,一串固定长度的字符连接起来的字符集合.Go语言的字符串是使用UTF-8编码的.UTF-8是Unicode的实现方式之一. Go语言原生支持字符串.使用双引号(“”)或反 ...

  6. css3动画性能优化--针对移动端卡顿问题

    一.使用css,jquery,canvas制作动画 1.Canvas 优点:性能好,强大,支持多数浏览器(除了IE6.IE7.IE8),画出来的图形可以直接保存为 .png 或者 .jpg的图形: 缺 ...

  7. LeetCode 910. Smallest Range II

    很有意思的一道数学推理题目, 剪枝以后解法也很简洁.初看貌似需要把每个数跟其他数作比较.但排序以后可以发现情况大大简化:对于任一对元素a[i] < a[j], a[i] - k和a[j] + k ...

  8. 初识Symbol

    Symbol作用域 Symbol,是ES6语法中新增的,值是由Symbol函数调用产生的. var s1 = Symbol(); console.log(s1); // Symbol console. ...

  9. 计算机专业C语言编程学习重点:指针化难为易

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  10. Hadoop HA高可用集群搭建(2.7.2)

    1.集群规划: 主机名        IP                安装的软件                            执行的进程 drguo1  192.168.80.149 j ...