C++对象内存分布(3) - 菱形继承(virtual)
1.前言
本篇文章的全部代码样例。假设是windows上编译执行。则使用的是visual studio 2013。假设是RHEL6.5平台(linux kernal: 2.6.32-431.el6.i686)上编译执行,则其gcc版本号为4.4.7,例如以下所看到的:
[root@MiWiFi-R1CM ~]# gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
2.菱形继承类的内存分布
本篇文章主要讨论的是虚继承(virtual)下的内存分布。
2.1.类的结构
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hsdHNo/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
2.2.实现代码windows版本号
以下的代码执行在windows 7+visual studio 2013平台上。
分别打印类Base1对象的内存分布。和类Derive对象的内存分布。
#include <iostream>
using namespace std;
class Base
{
public:
int _iBase;
char _cBase;
public:
Base() : _iBase(1111), _cBase('A')
{
}
virtual void func()
{
cout << "Base::func()" << endl;
}
virtual void baseFunc()
{
cout << "Base::baseFunc()" << endl;
}
}; class Base1 : public virtual Base
{
public:
int _iBase1;
char _cBase1;
public:
Base1() : _iBase1(2222), _cBase1('B')
{
}
virtual void func()
{
cout << "Base1::func()" << endl;
}
virtual void func1()
{
cout << "Base1::func1()" << endl;
}
virtual void baseFunc1()
{
cout << "Base1::baseFunc1()" << endl;
}
}; class Base2 : public virtual Base
{
public:
int _iBase2;
char _cBase2;
public:
Base2() : _iBase2(3333), _cBase2('C')
{
}
virtual void func()
{
cout << "Base2::func()" << endl;
}
virtual void func2()
{
cout << "Base2::func2()" << endl;
}
virtual void baseFunc2()
{
cout << "Base2::baseFunc2()" << endl;
}
}; class Derive : public virtual Base1, public virtual Base2
{
public:
int _iDerive;
char _cDerive;
public:
Derive() : _iDerive(4444), _cDerive('D')
{
}
virtual void func()
{
cout << "Derive::func()" << endl;
}
virtual void func1()
{
cout << "Derive::func1()" << endl;
}
virtual void func2()
{
cout << "Derive::func2()" << endl;
}
virtual void deriveFunc()
{
cout << "Derive::deriveFunc()" << endl;
}
}; typedef void(*Fun)(); int main() {
int **pVtab = NULL;
Fun pFun = NULL; Base1 bb1; cout << "sizeof(Base)" << sizeof(Base) << endl;
cout << "sizeof(Base1)" << sizeof(Base1) << endl; //Base1 layout
pVtab = (int**)&bb1;
cout << "[0] Base1::_vptr->" << " addr:" << &pVtab[0] << endl;
pFun = (Fun)pVtab[0][0];
cout << " [0]";
pFun(); //Base1::func1()
pFun = (Fun)pVtab[0][1];
cout << " [1]";
pFun(); //Base1::baseFunc1()
cout << " [2]";
cout << pVtab[0][2] << endl; cout << "[1] Base1::_vbptr->" << " addr:" << &pVtab[1] << endl;
cout << " [0]";
cout << pVtab[1][0] << endl;
cout << " [1]offset->";
cout << pVtab[1][1] << endl;
cout << " [2]";
cout << pVtab[1][2] << endl; cout << "[2] Base1:_iBase1 -> ";
cout << (int)pVtab[2] << endl; //Base1:_iBase1 cout << "[3] Base1:_cBase1 -> ";
cout << (char)(int)pVtab[3] << endl; //Base1:_cBase1 cout << "[4] unknown ";
cout << (int)pVtab[4] << endl; cout << "[5] Base::_vfptr->" << " addr:" << &pVtab[4] << endl;
cout << " [0]";
pFun = (Fun)pVtab[5][0];
pFun();
cout << " [1]";
pFun = (Fun)pVtab[5][1];
pFun();
cout << " [2]";
cout << (int)pVtab[5][2] << endl; cout << "[6] Base:_iBase -> ";
cout << (int)pVtab[6] << endl; //Base:_iBase cout << "[7] Base:_cBase -> ";
cout << (char)(int)pVtab[7] << endl; //Base:_cBase cout << endl;
cout << "###########################" << endl;
cout << endl; //Derive layout
// sub Derive vtbl layout
Derive d;
cout << "sizeof(Derive)" << sizeof(Derive) << endl; pVtab = (int**)&d;
cout << "[0] Derive::_vfptr->" << " addr:" << &pVtab[0] << endl;
cout << " [0] ";
pFun = (Fun)pVtab[0][0];
pFun(); //Derive::func1();
cout << " [1] ";
cout << pVtab[0][1] << endl; cout << "[1] Derive::_vbptr->" << " addr:" << &pVtab[1] << endl;
cout << " [0] ";
cout << pVtab[1][0] << endl;
cout << " [1]offset-> ";
cout << pVtab[1][1] << endl;
cout << " [2] ";
cout << pVtab[1][2] << endl;
cout << " [3] ";
cout << pVtab[1][3] << endl;
cout << " [4] ";
cout << pVtab[1][4] << endl; cout << "[2] Derive::_iDerive -> ";
cout << (int)pVtab[2] << endl; //Derive:_iDerive cout << "[3] Derive::_cDerive -> ";
cout << (char)(int)pVtab[3] << endl; //Derive::_cDerive cout << "[4] unknown-> " << (int)pVtab[4] << endl; // sub Base vtbl layout
cout << "[5] Base::_vfptr->" << " addr:" << &pVtab[5] << endl;
cout << " [0] ";
pFun = (Fun)pVtab[5][0];
pFun();
pFun = (Fun)pVtab[5][1];
cout << " [1] ";
pFun();
cout << " [2] ";
cout << pVtab[5][2] << endl; cout << "[6] Base::_iBase -> ";
cout << (int)pVtab[6] << endl; cout << "[7] Base::_cBase -> ";
cout << (char)(int)pVtab[7] << endl; cout << "[8] unknown-> ";
cout << (int)pVtab[8] << endl; // sub Base1 vtbl layout
cout << "[9] Base1::_vfptr->" << " addr:" << &pVtab[9] << endl;
cout << " [0] ";
cout << pVtab[9][0] << endl;
pFun = (Fun)pVtab[9][1];
cout << " [1] ";
pFun();
pFun = (Fun)pVtab[9][2];
cout << " [2] ";
cout << (int)pFun << endl;
pFun = (Fun)pVtab[9][3];
cout << " [3] ";
cout << (int)pFun << endl; cout << "[10] unknown-> ";
cout << (int)pVtab[10] << endl; cout << "[11] Base1::_iBase1 -> ";
cout << (int)pVtab[11] << endl; cout << "[12] Base1::_cBase1 -> ";
cout << (char)(int)pVtab[12] << endl; cout << "[13] unknown-> ";
cout << (int)pVtab[13] << endl; // sub Base2 vtbl layout
cout << "[14] Base2::_vfptr->" << " addr:" << &pVtab[14] << endl;
cout << " [0] ";
cout << pVtab[14][0] << endl;
pFun = (Fun)pVtab[14][1];
cout << " [1] ";
pFun();
cout << " [2] ";
cout << pVtab[14][2] << endl;
cout << " [3] ";
cout << pVtab[14][3] << endl; cout << "[15] unknown-> ";
cout << (int)pVtab[15] << endl; cout << "[16] Base2::_iBase2 -> ";
cout << (int)pVtab[16] << endl; cout << "[17] Base2::_cBase2 -> ";
cout << (char)(int)pVtab[17] << endl; return 0;
}
Base1对象的内存分布为:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hsdHNo/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
Derive对象的内存分布为:
2.3.实现代码linux版本号
以下代码中,对于这4个类的定义,与前面的windows代码中对类的定义是全然一样的,所以这里省略掉了。仅仅列出用于输出内存分布的代码:
int main()
{
int **pVtab = NULL;
Fun pFun = NULL; Base1 bb1; cout << "sizeof(Base)" << sizeof(Base) << endl;
cout << "sizeof(Base1)" << sizeof(Base1) << endl; //Base1 layout
pVtab = (int**)&bb1;
cout << "[0] Base1::_vptr->" << " addr:" << &pVtab[0] << endl;
pFun = (Fun)pVtab[0][0];
cout << " [0]";
pFun(); //Base1::func1()
pFun = (Fun)pVtab[0][1];
cout << " [1]";
pFun(); //Base1::baseFunc1()
pFun = (Fun)pVtab[0][2];
cout << " [2]";
pFun();
cout << " [3]";
cout << pVtab[0][3]; cout << "[1] Base1:_iBase1 -> ";
cout << (int)pVtab[1] << endl; //Base1:_iBase1 cout << "[2] Base1:_cBase1 -> ";
cout << (char)(int)pVtab[2] << endl; //Base1:_cBase1 // Base layout
cout << "[3] Base::_vptr->" << " addr:" << &pVtab[3] << endl;
pFun = (Fun)pVtab[3][0];
cout << " [0]";
pFun(); //Base1::func()
pFun = (Fun)pVtab[3][1];
cout << " [1]";
pFun(); //Base::baseFunc()
cout << " [2]";
cout << pVtab[3][2] << endl; cout << "[4] Base:_iBase -> ";
cout << (int)pVtab[4] << endl; //Base:_iBase
cout << "[5] Base:_cBase -> ";
cout << (char)(int)pVtab[5] << endl; //Base:_cBase cout << "[6] " << (int)pVtab[6] << " addr:" << &pVtab[6] << endl; //dirty data cout << endl;
cout << "###########################" << endl;
cout << endl; // Derive layout
// sub Derive vtbl layout
Derive d;
cout << "sizeof(Derive)" << sizeof(Derive) << endl; pVtab = (int**)&d;
cout << "[0] Derive::_vfptr->" << " addr:" << &pVtab[0] << endl;
cout << " [0] ";
pFun(); //Derive::func1();
pFun = (Fun)pVtab[0][1];
cout << " [1] ";
pFun(); //Base1::baseFunc1();
pFun = (Fun)pVtab[0][2];
cout << " [2] ";
pFun(); //Derive::deriveFunc();
pFun = (Fun)pVtab[0][3];
cout << " [3] ";
pFun();
cout << " [4] ";
cout << pVtab[0][4] << endl; cout << "[1] Derive:_iDerive -> ";
cout << (int)pVtab[1] << endl; //Derive:_iDerive cout << "[2] Derive:_cDerive -> ";
cout << (char)(int)pVtab[2] << endl; //Derive:_cDerive // sub Base1 vtbl layout
cout << "[3] Base1::_vptr->" << " addr:" << &pVtab[3] << endl;
pFun = (Fun)pVtab[3][0];
cout << " [0] ";
pFun();
pFun = (Fun)pVtab[3][1];
cout << " [1] ";
pFun();
pFun = (Fun)pVtab[3][2];
cout << " [2] ";
pFun();
cout << " [3] ";
cout << pVtab[3][3] << endl; cout << "[4] Base1::_iBase1 -> ";
cout << (int)pVtab[4] << endl; cout << "[5] Base1::_cBase1 -> ";
cout << (char)(int)pVtab[5] << endl; // sub Base vtbl layout
cout << "[6] Base::_vptr->" << " addr:" << &pVtab[6] << endl;
pFun = (Fun)pVtab[6][0];
cout << " [0] ";
pFun();
pFun = (Fun)pVtab[6][1];
cout << " [1] ";
pFun();
pFun = (Fun)pVtab[6][2];
cout << " [2] ";
cout << (int)pFun << endl; cout << "[7] Base::_iBase -> ";
cout << (int)pVtab[7] << endl; cout << "[8] Base::_cBase -> ";
cout << (char)(int)pVtab[8] << endl; // sub Base2 vtbl layout
cout << "[9] Base2::_vptr->" << " addr:" << &pVtab[9] << endl;
pFun = (Fun)pVtab[9][0];
cout << " [0] ";
pFun();
pFun = (Fun)pVtab[9][1];
cout << " [1] ";
pFun();
pFun = (Fun)pVtab[9][2];
cout << " [2] ";
pFun();
cout << " [3] ";
cout << pVtab[9][3] << endl; cout << "[10] Base2::_iBase2 -> ";
cout << (int)pVtab[10] << endl; cout << "[11] Base2::_cBase2 -> ";
cout << (char)(int)pVtab[11] << endl; return 0;
}
Base1对象的内存分布为:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hsdHNo/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
Derive对象的内存分布为:
2.4.Base1类的内存分布对照
Windows 7 + Visual studio 2013 Linux RHEL6.5 + gcc 4.4.7
2.5.Derive类的内存分布对照
Windows 7 + Visual studio 2013 Linux RHEL6.5 + gcc 4.4.7
2.6.Derive类在虚继承与非虚继承中的内存对照
在前面的章节(2.5)中,已经列出了Derive在虚继承(virtual)的情况下,在windows以及linux平台下的具体内存分布。
在前一篇文章中,我们获得了非虚继承(non virtual)的情况下,Derive类的内存分布。
这里将它与本篇文章中获得的虚继承的分布。进行一个对照。
下图是windows平台下。非虚继承与虚继承对类的内存分布的影响对照。
非虚继承(non virtual) 虚继承(virtual)
下图是linux平台下。非虚继承与虚继承对类的内存分布的影响对照。
非虚继承(non virtual) 虚继承(virtual)
C++对象内存分布(3) - 菱形继承(virtual)的更多相关文章
- C++对象内存分布详解(包括字节对齐和虚函数表)
转自:https://www.jb51.net/article/101122.htm 1.C++对象的内存分布和虚函数表: C++对象的内存分布和虚函数表注意,对象中保存的是虚函数表指针,而不是虚函数 ...
- Java对象内存分布
[deerhang] 创建对象的四种方式:new关键字.反射.Object.clone().unsafe方法 new和反射是通过调用构造器创建对象的,创建对象的时候使用invokespecial指令 ...
- 记录:C++类内存分布(虚继承与虚函数)
工具:VS2013 先说一下VS环境下查看类内存分布的方法: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存 ...
- 【C++ Primer | 15】C++类内存分布
C++类内存分布 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看编译器是怎么处理类成员内存分布的,特别是在继承.虚函数存在的情况下. 下面可以定义一个类,像下面这样: c ...
- 图说C++对象模型:对象内存布局详解
0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...
- c++ 对象内存布局详解
今天看了的,感觉需要了解对象内存的问题.参考:http://blog.jobbole.com/101583/ 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个 ...
- 好文章系列C/C++——图说C++对象模型:对象内存布局详解
注:收藏好文章,得出自己的笔记,以查漏补缺! ------>原文链接:http://blog.jobbole.com/101583/ 前言 本文可加深对C++对象的内存布局.虚表指针.虚 ...
- 【转载】图说C++对象模型:对象内存布局详解
原文: 图说C++对象模型:对象内存布局详解 正文 回到顶部 0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看.本文的结论都在 ...
- C++类虚函数内存分布(这个 你必须懂)
转自:http://www.cnblogs.com/jerry19880126/p/3616999.html C++类内存分布 书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来 ...
随机推荐
- 对socket的理解
要想理解socket,就得先熟悉TCP/IP协议族,TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如 ...
- Docker在Ubuntu16.04上安装
转自:http://blog.51cto.com/collen7788/2047800 1.添加Docker源 sudo apt-get update 2.增加CA证书 sudo apt-get in ...
- SQL SERVER 执行计划各字段注释
SET SHOWPLAN_ALL使 Microsoft® SQL Server™ 不执行 Transact-SQL 语句.相反,SQL Server 返回有关语句执行方式和语句预计所需资源的详细信息. ...
- Android(java)学习笔记205:JNI之编写jni程序适配所有处理器型号
1. 还是以"02_两个数相加"为例,你会发现这个jni程序只能在ARM处理器下运行,如下: 如果我们让上面的程序运行在x86模拟器上,处理平台不对应,报如下错误: 03-29 ...
- 服务器主机&软件性能测试自定标准
PS:最近一直致力于代理ip的服务搭建,其中就要根据客户群体的不同来测试搭建环境和搭建软件的性能,但是不同的客户群体所处的环境和使用的软件是不同的,而业内又没有一套完整的评估方法.在忽略网络本身来讲, ...
- Vue课程思维导图
- Vue指令5:v-if
条件判断(v-if\v-else) v-if 指令将根据表达式的真假值(true 或 false )来决定是否插入 元素. <div id="app"> <ul ...
- MxCAD5.2 20181022更新
下载地址: http://www.mxdraw.com/ndetail_10108.html 1. 开放VIP功能,无需购买即可使用 2. 修正一些图纸打开和保存出错的问题 3. 修改填充命令,对某些 ...
- 安装svn
一.安装 1.查看是否安装cvs rpm -qa | grep subversion 2.安装 yum install subversion 3.测试是否安装成功 /usr/bin/svnserve ...
- day02 Python完结
一. 常用数据类型及内置法 1 列表 定义: 列表是Python中内置有序.可变序列,列表的所有元素放在一对中括号“[]”中,并使用逗号分隔开: 当列表元素增加或删除时,列表对象自动进行扩展或收缩内存 ...