C++内存布局

转自http://www.cnblogs.com/kekec/archive/2013/01/27/2822872.html

#类中的元素

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). 只有成员变量的类

C++内存布局_第1张图片

int nVarSize = sizeof(CVariable) = 12

 C++内存布局_第2张图片

内存布局:

(3). 只有虚函数的类

C++内存布局_第3张图片

int nVFuntionSize = sizeof(CVFuction) = 4(虚表指针)

 C++内存布局_第4张图片

内存布局:

(4). 有成员变量、虚函数的类

C++内存布局_第5张图片 

int nParentSize = sizeof(CParent) = 8

C++内存布局_第6张图片

内存布局:

1. 单一继承(含成员变量、虚函数、虚函数覆盖)

C++内存布局_第7张图片

int nChildSize = sizeof(CChildren) = 12

vc中显示的结果(注:还有1个虚函数CChildren::g1没有被显示出来):

C++内存布局_第8张图片

d1reportSingleClass查看:

C++内存布局_第9张图片

内存布局:

2. 多继承 (含成员变量、虚函数、虚函数覆盖)

C++内存布局_第10张图片

int nChildSize = sizeof(CChildren) = 20

vc中显示的结果(注:还有2个虚函数CChildren::f2,CChildren::h2没有被显示出来,this指针的adjustor[调整值]也没打印出):

C++内存布局_第11张图片

d1reportSingleClass查看:

C++内存布局_第12张图片

内存布局:

C++内存布局_第13张图片

3. 深度为2的继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第14张图片

int nGrandSize = sizeof(CGrandChildren) = 24

vc中显示的结果(注:还有3个虚函数CGrandChildren::f2,CChildren::h2,CGrandChildren::f3没有显示出来,this指针的adjustor[调整值]也没打印出):

C++内存布局_第15张图片

d1reportSingleClass查看:

C++内存布局_第16张图片

内存布局:

C++内存布局_第17张图片

4 重复继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第18张图片

int nGrandSize = sizeof(CGrandChildren) = 28

vc中显示的结果(注:还有大量的虚函数没有显示出来,this指针的adjustor[调整值]也没打印出):

thunk函数:一种形实转换辅助函数;主要做this指针调整函数调用重定向

C++内存布局_第19张图片

d1reportSingleClass查看:

C++内存布局_第20张图片

内存布局:

C++内存布局_第21张图片

由于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. 单一虚继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第22张图片

int nChildSize = sizeof(CChildren) = 20

d1reportSingleClass查看:

C++内存布局_第23张图片

内存布局:

 C++内存布局_第24张图片

6. 多虚继承(含成员变量、虚函数、虚函数覆盖)

(1) virtual CParent1, CParent2

C++内存布局_第25张图片

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

C++内存布局_第26张图片

内存布局:

C++内存布局_第27张图片

(2) CParent1, virtual CParent2

C++内存布局_第28张图片

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

C++内存布局_第29张图片

内存布局:

C++内存布局_第30张图片

(3) virtual CParent1, virtual CParent2

C++内存布局_第31张图片

int nChildSize = sizeof(CChildren) = 28

d1reportSingleClass查看:

C++内存布局_第32张图片

内存布局:

C++内存布局_第33张图片

7. 钻石型的虚拟多重继承(含成员变量、虚函数、虚函数覆盖)

C++内存布局_第34张图片

int nGrandChildSize = sizeof(CGrandChildren) = 36

d1reportSingleClass查看:

thunk函数:一种形实转换辅助函数;主要做this指针调整函数调用重定向

C++内存布局_第35张图片

内存布局:

C++内存布局_第36张图片

#外部参考

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). 只有成员变量的类

C++内存布局_第37张图片

int nVarSize = sizeof(CVariable) = 12

 C++内存布局_第38张图片

内存布局:

(3). 只有虚函数的类

C++内存布局_第39张图片

int nVFuntionSize = sizeof(CVFuction) = 4(虚表指针)

 C++内存布局_第40张图片

内存布局:

(4). 有成员变量、虚函数的类

C++内存布局_第41张图片 

int nParentSize = sizeof(CParent) = 8

C++内存布局_第42张图片

内存布局:

1. 单一继承(含成员变量、虚函数、虚函数覆盖)

C++内存布局_第43张图片

int nChildSize = sizeof(CChildren) = 12

vc中显示的结果(注:还有1个虚函数CChildren::g1没有被显示出来):

C++内存布局_第44张图片

d1reportSingleClass查看:

C++内存布局_第45张图片

内存布局:

2. 多继承 (含成员变量、虚函数、虚函数覆盖)

C++内存布局_第46张图片

int nChildSize = sizeof(CChildren) = 20

vc中显示的结果(注:还有2个虚函数CChildren::f2,CChildren::h2没有被显示出来,this指针的adjustor[调整值]也没打印出):

C++内存布局_第47张图片

d1reportSingleClass查看:

C++内存布局_第48张图片

内存布局:

C++内存布局_第49张图片

3. 深度为2的继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第50张图片

int nGrandSize = sizeof(CGrandChildren) = 24

vc中显示的结果(注:还有3个虚函数CGrandChildren::f2,CChildren::h2,CGrandChildren::f3没有显示出来,this指针的adjustor[调整值]也没打印出):

C++内存布局_第51张图片

d1reportSingleClass查看:

C++内存布局_第52张图片

内存布局:

C++内存布局_第53张图片

4 重复继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第54张图片

int nGrandSize = sizeof(CGrandChildren) = 28

vc中显示的结果(注:还有大量的虚函数没有显示出来,this指针的adjustor[调整值]也没打印出):

thunk函数:一种形实转换辅助函数;主要做this指针调整函数调用重定向

C++内存布局_第55张图片

d1reportSingleClass查看:

C++内存布局_第56张图片

内存布局:

C++内存布局_第57张图片

由于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. 单一虚继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第58张图片

int nChildSize = sizeof(CChildren) = 20

d1reportSingleClass查看:

C++内存布局_第59张图片

内存布局:

 C++内存布局_第60张图片

6. 多虚继承(含成员变量、虚函数、虚函数覆盖)

(1) virtual CParent1, CParent2

C++内存布局_第61张图片

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

C++内存布局_第62张图片

内存布局:

C++内存布局_第63张图片

(2) CParent1, virtual CParent2

C++内存布局_第64张图片

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

C++内存布局_第65张图片

内存布局:

C++内存布局_第66张图片

(3) virtual CParent1, virtual CParent2

C++内存布局_第67张图片

int nChildSize = sizeof(CChildren) = 28

d1reportSingleClass查看:

C++内存布局_第68张图片

内存布局:

C++内存布局_第69张图片

7. 钻石型的虚拟多重继承(含成员变量、虚函数、虚函数覆盖)

C++内存布局_第70张图片

int nGrandChildSize = sizeof(CGrandChildren) = 36

d1reportSingleClass查看:

thunk函数:一种形实转换辅助函数;主要做this指针调整函数调用重定向

C++内存布局_第71张图片

内存布局:

C++内存布局_第72张图片

#外部参考

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). 只有成员变量的类

C++内存布局_第73张图片

int nVarSize = sizeof(CVariable) = 12

 C++内存布局_第74张图片

内存布局:

(3). 只有虚函数的类

C++内存布局_第75张图片

int nVFuntionSize = sizeof(CVFuction) = 4(虚表指针)

 C++内存布局_第76张图片

内存布局:

(4). 有成员变量、虚函数的类

C++内存布局_第77张图片 

int nParentSize = sizeof(CParent) = 8

C++内存布局_第78张图片

内存布局:

1. 单一继承(含成员变量、虚函数、虚函数覆盖)

C++内存布局_第79张图片

int nChildSize = sizeof(CChildren) = 12

vc中显示的结果(注:还有1个虚函数CChildren::g1没有被显示出来):

C++内存布局_第80张图片

d1reportSingleClass查看:

C++内存布局_第81张图片

内存布局:

2. 多继承 (含成员变量、虚函数、虚函数覆盖)

C++内存布局_第82张图片

int nChildSize = sizeof(CChildren) = 20

vc中显示的结果(注:还有2个虚函数CChildren::f2,CChildren::h2没有被显示出来,this指针的adjustor[调整值]也没打印出):

C++内存布局_第83张图片

d1reportSingleClass查看:

C++内存布局_第84张图片

内存布局:

C++内存布局_第85张图片

3. 深度为2的继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第86张图片

int nGrandSize = sizeof(CGrandChildren) = 24

vc中显示的结果(注:还有3个虚函数CGrandChildren::f2,CChildren::h2,CGrandChildren::f3没有显示出来,this指针的adjustor[调整值]也没打印出):

C++内存布局_第87张图片

d1reportSingleClass查看:

C++内存布局_第88张图片

内存布局:

C++内存布局_第89张图片

4 重复继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第90张图片

int nGrandSize = sizeof(CGrandChildren) = 28

vc中显示的结果(注:还有大量的虚函数没有显示出来,this指针的adjustor[调整值]也没打印出):

thunk函数:一种形实转换辅助函数;主要做this指针调整函数调用重定向

C++内存布局_第91张图片

d1reportSingleClass查看:

C++内存布局_第92张图片

内存布局:

C++内存布局_第93张图片

由于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. 单一虚继承(含成员变量、虚函数、虚函数覆盖)

 C++内存布局_第94张图片

int nChildSize = sizeof(CChildren) = 20

d1reportSingleClass查看:

C++内存布局_第95张图片

内存布局:

 C++内存布局_第96张图片

6. 多虚继承(含成员变量、虚函数、虚函数覆盖)

(1) virtual CParent1, CParent2

C++内存布局_第97张图片

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

C++内存布局_第98张图片

内存布局:

C++内存布局_第99张图片

(2) CParent1, virtual CParent2

C++内存布局_第100张图片

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

C++内存布局_第101张图片

内存布局:

C++内存布局_第102张图片

(3) virtual CParent1, virtual CParent2

C++内存布局_第103张图片

int nChildSize = sizeof(CChildren) = 28

d1reportSingleClass查看:

C++内存布局_第104张图片

内存布局:

C++内存布局_第105张图片

7. 钻石型的虚拟多重继承(含成员变量、虚函数、虚函数覆盖)

C++内存布局_第106张图片

int nGrandChildSize = sizeof(CGrandChildren) = 36

d1reportSingleClass查看:

thunk函数:一种形实转换辅助函数;主要做this指针调整函数调用重定向

C++内存布局_第107张图片

内存布局:

C++内存布局_第108张图片

#外部参考

C++类对应的内存结构

陈皓- C++ 虚函数表解析

陈皓 - C++ 对象的内存布局(上)

陈皓 - C++ 对象的内存布局(下)

你可能感兴趣的:(C++内存布局)