转载自http://blog.csdn.net/it_yuan/article/details/24651347

#类中的元素

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++ 对象的内存布局(下)

参考链接:http://blog.csdn.net/yangshuangtao/article/details/45192149

c++内存对齐原理的更多相关文章

  1. C语言内存对齐原理

    一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这 ...

  2. 重磅硬核 | 一文聊透对象在 JVM 中的内存布局,以及内存对齐和压缩指针的原理及应用

    欢迎关注公众号:bin的技术小屋 大家好,我是bin,又到了每周我们见面的时刻了,我的公众号在1月10号那天发布了第一篇文章<从内核角度看IO模型的演变>,在这篇文章中我们通过图解的方式以 ...

  3. C/C++: C++位域和内存对齐问题

    1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...

  4. C语言再学习之内存对齐

    昨天看Q3的代码,看到有个_INTSAIZEOF的宏,着实晕了一阵.一番google后,终于明白,这个宏的作用是求出变量占用内存空间的大小,先看看_INTSAIZEOF的定义吧: #define _I ...

  5. C结构体中数据的内存对齐问题

    转自:http://www.cnblogs.com/qwcbeyond/archive/2012/05/08/2490897.html 32位机一般默认4字节对齐(32位机机器字长4字节),64位机一 ...

  6. 2的m次方 内存对齐

    在存储的时候,为了提高效率,一般都会让偏移量落在2的m次方的位置上,而且常有向上取整和向下取整两种需求.向下取整PALIGN_DOWN(x,align)  (x & (- align)) 这样 ...

  7. Net的struct的内存对齐问题

    很少有人谈起struct的内存对齐问题, 就是在很多C#书中, 也很少提及. 但在实际应用中, 如果不注意内存对齐, struct比较大的话, 则会浪费一定的内存.    先从一个实例看起. publ ...

  8. c++中类对象的内存对齐

    很多C++书籍中都介绍过,一个Class对象需要占用多大的内存空间.最权威的结论是: *非静态成员变量总合.(not static) *加上编译器为了CPU计算,作出的数据对齐处理.(c语言中面试中经 ...

  9. C/C++中的内存对齐问题和pragma pack命令详解

    这个内存对齐问题,居然影响到了sizeof(struct)的结果值.突然想到了之前写的一个API库里,有个API是向后台服务程序发送socket请求.其中的socket数据包是一个结构体.在发送soc ...

随机推荐

  1. vue中computed和watch

    computed 计算属性 能够监听vue数据上的变化,页面上来就执行一次,每改变一次数据就又触发.在操作数据的时候,会派生出另一个事情 1.函数形式 computed:{ listenArr(){ ...

  2. oldboy s21day02

    1.猜数字,设定一个理想数字比如:66,让用户输入数字,如果比66大,则显示猜测的结果大了:如果比66小,则显示猜测的结果小了;只有等于66,显示猜测结果正确,然后退出循环.while 1: num ...

  3. [Android] Android ViewPager 中加载 Fragment的两种方式 方式(二)

    接上文: https://www.cnblogs.com/wukong1688/p/10693338.html Android ViewPager 中加载 Fragmenet的两种方式 方式(一) 二 ...

  4. 细说java系统之动态代理

    代理模式 在深入学习动态代理之前,需要先掌握代理模式.只有深刻理解了代理模式的应用,才能充分理解Java动态代理带来的便利. 在生活中存在许多使用"代理模式"的场景,比如:村里的张 ...

  5. Android设置状态栏颜色

    1.代码设置if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window window = this.getWindow ...

  6. Play XML Entities

    链接:https://pentesterlab.com/exercises/play_xxe/course Introduction This course details the exploitat ...

  7. hackrf入门

    http://www.hackrf.net/hackrf%E4%B8%8Egnuradio%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/

  8. 最好用的js前端框架、组件、文档在线预览插件

    这里收集的都是个人认为比较好的js框架.组件 js前端ui框架 此处列举出个人认为最好的几个框架(排序即排名),现在好点的框架商用都需要付费,以下几个也不例外,但是由于组件丰富,都可以作为企业应用的完 ...

  9. javascript 正则表达式总结

    为什么要使用正则表达式 正则表达式通过由普通字符和特殊字符组成的文字模板完成对字符串的校验,搜索,替换.在javascript中类似这样 /^1\d{10}$/ 复制代码 上面的这个简单的正则用来匹配 ...

  10. Express 体验 路由、模板引擎、中间件

    http://expressjs.com/en/4x/api.html#req.method http://expressjs.com/en/guide/routing.html [Route pat ...