对于普通的C++对象内存布局,简单得不得了,就不做总结了。这里只总结涉及到虚拟继承的情况。
因为不同编译器对虚拟继承的实现采用不同的方式,所以要完整的分析是不可能的。这里只考虑VS2005/2008,还有简单涉及GCC编译器。
1、
单个虚拟继承
只是为了分析而已,实际中并没有太大的作用。跟虚拟继承相关的派生类对象的内存布局跟具体的编译器相关。
(1)VS编译器:无论有无虚函数,必然含有虚基类表指针。虚基类表中的内容为本类实例的偏移和基类实例的相对偏移值。如果有虚函数,那么基类的虚函数表跟派生类的虚函数表是分开的。
在内存布局上,地址从低到高,顺序如下:派生类的虚函数表指针+虚基类表指针+派生类的成员变量+“间隔”(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编译器则没有这么做,测试了比较简单的情况,发现它做了优化,并没有利用虚基类表,而是直接在派生类对象地址上加上一个常数,获得虚基类实例的地址。
分享到:
相关推荐
涉及各种情况下C++对象的sizeof大小,包括单一类对象,继承,重复继承 多继承 单一虚继承 等各种情况下的对象大小。对C++对象内存布局有清楚了解。
C++对象内存布局[归类].pdf
介绍C++对象在内存中是怎样分布的,有助于深层学习C++。
详细理解vs2008C++编程内存使用情况!!值得一看...
c++ 标准不规定 c++ 实现的时候的对象的具体的内存布局,除了在某些方面有小的限制以外,c++ 对象在内存里面的布局完全是由编译器自行决定,这里只是讨论 vc++ .net 2003 build 7.1.3091 的实现方式.
看了这个内存布局图详解之后,对于C++的了解更加深刻了,之前不懂得一头雾水的东西全都清楚了。
C++ 对象的内存布局。全面分析C++ 对象的内存布局。
C++对象内存模型.pdf
安卓逆向学习笔记之ART中的C++对象内存布局及获取art-method和dex-file对象.docx
1)有成员变量的情况。 2)有重复继承的情况。 3)有虚拟继承的情况。 4)有钻石型虚拟继承的情况。
c++对象的内存布局 对c++做了非常通俗 而且经典的分析 如果你想对c++的工作方式有更深入的了解 这是一份非常有帮助的文档
C++对象模型在内存中的实现,讲述了类,继承以及虚继承的内存布局;成员变量和成员函数的访问已经访问时的开销情况,包含虚函数的情况,考察构造函数,析构函数,以及特殊的赋值操作符成员函数是如何工作的,数组是...
C++ 对象的内存布局(下)1
c++多态内存布局1
C++对象的内存布局[归纳].pdf
1* 类如何布局? 2* 成员变量如何访问? 3* 成员函数如何访问? 4* 所谓的“调整块”(adjuster thunk)是怎么回事? 5* 使用如下机制时,开销如何: * 单继承、多重继承、虚继承 * 虚函数调用 * 强制转换...
第8章 C++对象模型总结 8.1 C++对象模型 8.2 单继承 8.2.1 无重写的单继承 8.2.2 有重写的单继承 8.3 多继承 8.4 虚拟继承 8.4.1 简单虚继承(无重复继承) 8.4.2 菱形继承(含重复继承、多继承情况) 8.5 相关问题 ...
这是一些关于基类含有virtual函数或子类是virtual继承的对象的内存布局。其中有我截的一些图、内存布局图、文字说明,不过能力有限,说的不是很清楚,望谅解
C++对象内存池 ---- C++侦探改写.rar
验证C++对象模型,对C++中类及对象的内存布局做了详细说明,并使用代码验证模型