C++对象内存布局
2015-08-24 13:17
260 查看
#类中的元素
0. 成员变量 1. 成员函数 2. 静态成员变量 3. 静态成员函数
4. 虚函数 5. 纯虚函数
#影响对象大小的因素
0. 成员变量 1. 虚函数表指针(_vftptr) 2. 虚基类表指针(_vbtptr)
3. 内存对齐
_vftptr、_vbtptr的初始化由对象的构造函数, 赋值运算符自动完成;对象生命周期结束后,由对象的析构函数来销毁。
对象所关联的类型(type_info),通常放在virtual table的第一个slot中。
虚继承:在继承定义中包含了virtual关键字的继承关系;
虚基类:在虚继承体系中的通过virtual继承而来的基类,需要注意的是:
class CDerive : public virtual CBase {}; 其中CBase称之为CDerive的虚基类,而不是说CBase就是个虚基类,因为CBase还可以为不是虚继承体系中的基类。
虚函数被派生后,仍然为虚函数,即使在派生类中省去virtual关键字。
注:【下文中_vbptr即_vbtptr】
#对象内存布局分类讨论
vc6变量查看器中(Locals,Watch1等),也可以看到部分对象布局的情况(不完整,且虚继承是错误的)。
vs2005及以后版本的编译器提供了/d1reportSingleClassLayout[类名]编译选项来查看对象完整的内存布局:
0. 单一类
(1). 空类
sizeof(CNull)=1(用于标识该对象)
(2). 只有成员变量的类
int nVarSize = sizeof(CVariable) = 12
内存布局:
(3). 只有虚函数的类
int nVFuntionSize = sizeof(CVFuction) = 4(虚表指针)
内存布局:
(4). 有成员变量、虚函数的类
int nParentSize = sizeof(CParent) = 8
内存布局:
1. 单一继承(含成员变量、虚函数、虚函数覆盖)
int nChildSize = sizeof(CChildren)
= 12
vc中显示的结果(注:还有1个虚函数CChildren::g1没有被显示出来):
d1reportSingleClass查看:
内存布局:
2. 多继承 (含成员变量、虚函数、虚函数覆盖)
int nChildSize = sizeof(CChildren) = 20
vc中显示的结果(注:还有2个虚函数CChildren::f2,CChildren::h2没有被显示出来,this指针的adjustor[调整值]也没打印出):
d1reportSingleClass查看:
内存布局:
3. 深度为2的继承(含成员变量、虚函数、虚函数覆盖)
int nGrandSize = sizeof(CGrandChildren) = 24
vc中显示的结果(注:还有3个虚函数CGrandChildren::f2,CChildren::h2,CGrandChildren::f3没有显示出来,this指针的adjustor[调整值]也没打印出):
d1reportSingleClass查看:
内存布局:
4 重复继承(含成员变量、虚函数、虚函数覆盖)
int nGrandSize = sizeof(CGrandChildren) = 28
vc中显示的结果(注:还有大量的虚函数没有显示出来,this指针的adjustor[调整值]也没打印出):
thunk函数:一种形实转换辅助函数;主要做this指针调整,函数调用重定向。
d1reportSingleClass查看:
内存布局:
由于m_nAge在内容中存在两个拷贝,因此我们不能直接通过pGrandChildrenA->m_nAge来访问该变量,
这样会存在二义性,编译器无法知道应该访问CChildren1中的m_nAge,还是CChildren2中的m_nAge。
为了标识唯一的m_nAge,就需要带上其所在范围的类名了。如下:
5. 单一虚继承(含成员变量、虚函数、虚函数覆盖)
int nChildSize = sizeof(CChildren) = 20
d1reportSingleClass查看:
内存布局:
6. 多虚继承(含成员变量、虚函数、虚函数覆盖)
(1) virtual CParent1, CParent2
int nChildSize = sizeof(CChildren) = 24
d1reportSingleClass查看:
内存布局:
(2) CParent1, virtual CParent2
int nChildSize = sizeof(CChildren) = 24
d1reportSingleClass查看:
内存布局:
(3) virtual CParent1, virtual CParent2
int nChildSize = sizeof(CChildren) = 28
d1reportSingleClass查看:
内存布局:
7. 钻石型的虚拟多重继承(含成员变量、虚函数、虚函数覆盖)
int nGrandChildSize = sizeof(CGrandChildren) = 36
d1reportSingleClass查看:
thunk函数:一种形实转换辅助函数;主要做this指针调整,函数调用重定向。
内存布局:
#外部参考
C++类对应的内存结构
陈皓- C++ 虚函数表解析
陈皓 - C++ 对象的内存布局(上)
陈皓 - C++ 对象的内存布局(下)
0. 成员变量 1. 成员函数 2. 静态成员变量 3. 静态成员函数
4. 虚函数 5. 纯虚函数
#影响对象大小的因素
0. 成员变量 1. 虚函数表指针(_vftptr) 2. 虚基类表指针(_vbtptr)
3. 内存对齐
_vftptr、_vbtptr的初始化由对象的构造函数, 赋值运算符自动完成;对象生命周期结束后,由对象的析构函数来销毁。
对象所关联的类型(type_info),通常放在virtual table的第一个slot中。
虚继承:在继承定义中包含了virtual关键字的继承关系;
虚基类:在虚继承体系中的通过virtual继承而来的基类,需要注意的是:
class CDerive : public virtual CBase {}; 其中CBase称之为CDerive的虚基类,而不是说CBase就是个虚基类,因为CBase还可以为不是虚继承体系中的基类。
虚函数被派生后,仍然为虚函数,即使在派生类中省去virtual关键字。
注:【下文中_vbptr即_vbtptr】
#对象内存布局分类讨论
vc6变量查看器中(Locals,Watch1等),也可以看到部分对象布局的情况(不完整,且虚继承是错误的)。
vs2005及以后版本的编译器提供了/d1reportSingleClassLayout[类名]编译选项来查看对象完整的内存布局:
cl classLayout.cpp /d1reportSingleClassLayoutCChildren
0. 单一类
(1). 空类
sizeof(CNull)=1(用于标识该对象)
(2). 只有成员变量的类
int nVarSize = sizeof(CVariable) = 12
内存布局:
(3). 只有虚函数的类
int nVFuntionSize = sizeof(CVFuction) = 4(虚表指针)
内存布局:
(4). 有成员变量、虚函数的类
int nParentSize = sizeof(CParent) = 8
内存布局:
1. 单一继承(含成员变量、虚函数、虚函数覆盖)
int nChildSize = sizeof(CChildren)
= 12
vc中显示的结果(注:还有1个虚函数CChildren::g1没有被显示出来):
d1reportSingleClass查看:
内存布局:
2. 多继承 (含成员变量、虚函数、虚函数覆盖)
int nChildSize = sizeof(CChildren) = 20
vc中显示的结果(注:还有2个虚函数CChildren::f2,CChildren::h2没有被显示出来,this指针的adjustor[调整值]也没打印出):
d1reportSingleClass查看:
内存布局:
3. 深度为2的继承(含成员变量、虚函数、虚函数覆盖)
int nGrandSize = sizeof(CGrandChildren) = 24
vc中显示的结果(注:还有3个虚函数CGrandChildren::f2,CChildren::h2,CGrandChildren::f3没有显示出来,this指针的adjustor[调整值]也没打印出):
d1reportSingleClass查看:
内存布局:
4 重复继承(含成员变量、虚函数、虚函数覆盖)
int nGrandSize = sizeof(CGrandChildren) = 28
vc中显示的结果(注:还有大量的虚函数没有显示出来,this指针的adjustor[调整值]也没打印出):
thunk函数:一种形实转换辅助函数;主要做this指针调整,函数调用重定向。
d1reportSingleClass查看:
内存布局:
由于m_nAge在内容中存在两个拷贝,因此我们不能直接通过pGrandChildrenA->m_nAge来访问该变量,
这样会存在二义性,编译器无法知道应该访问CChildren1中的m_nAge,还是CChildren2中的m_nAge。
为了标识唯一的m_nAge,就需要带上其所在范围的类名了。如下:
1 pGrandChildrenA->CChildren1::m_nAge = 1; 2 pGrandChildrenA->CChildren2::m_nAge = 2;
5. 单一虚继承(含成员变量、虚函数、虚函数覆盖)
int nChildSize = sizeof(CChildren) = 20
d1reportSingleClass查看:
内存布局:
6. 多虚继承(含成员变量、虚函数、虚函数覆盖)
(1) virtual CParent1, CParent2
int nChildSize = sizeof(CChildren) = 24
d1reportSingleClass查看:
内存布局:
(2) CParent1, virtual CParent2
int nChildSize = sizeof(CChildren) = 24
d1reportSingleClass查看:
内存布局:
(3) virtual CParent1, virtual CParent2
int nChildSize = sizeof(CChildren) = 28
d1reportSingleClass查看:
内存布局:
7. 钻石型的虚拟多重继承(含成员变量、虚函数、虚函数覆盖)
int nGrandChildSize = sizeof(CGrandChildren) = 36
d1reportSingleClass查看:
thunk函数:一种形实转换辅助函数;主要做this指针调整,函数调用重定向。
内存布局:
#外部参考
C++类对应的内存结构
陈皓- C++ 虚函数表解析
陈皓 - C++ 对象的内存布局(上)
陈皓 - C++ 对象的内存布局(下)
相关文章推荐
- Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记
- 阿里巴巴2016校园招聘在线笔试(C/C++)附加题 第二题
- Machine Schedule
- 《算法导论》中求最大子数组的C++实现
- C++ Primer 5e chapter 15.1
- [C++]Reverse Integer整数翻转
- c++程序的内存布局
- C++ STL
- C++ Tips: 在控制台中显示中文
- 详解C语言中index()函数和rindex()函数的用法
- 在C语言中比较两个字符串是否相等的方法
- 【C++】不要在构造函数或析构函数内调用虚函数
- 在C++代码中调用L脚本语言
- [C++]Excel Sheet Column Title
- C语言中查找字符在字符串中出现的位置的方法
- C语言中strspn()函数和strcspn()函数的对比使用
- C++ 初始化列表
- vc++6.0 字节运算
- 详解C语言中strcpy()函数与strncpy()函数的使用
- 阿里巴巴2016年秋季校园招聘C++研发岗在线笔试附加题第一题