推荐阅读:http://blog.csdn.net/randyjiawenjie/article/details/6693337

最近研究了一下,C++继承的内存对象模型。主要是读了读http://blog.csdn.net/haoel/article/details/3081328C++ 对象的内存布局)。很推荐这篇文章。

对这篇文章做了做总结。本文的大部分内容来自于这篇文章中的总结http://blog.csdn.net/haoel/article/details/3081328(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++学习笔记----4.5 C++继承时的对象内存模型的更多相关文章

  1. C++ 学习笔记 (七)继承与多态 virtual关键字的使用场景

    在上一篇 C++ 学习笔记 (六) 继承- 子类与父类有同名函数,变量 中说了当父类子类有同名函数时在外部调用时如果不加父类名则会默认调用子类的函数.C++有函数重写的功能需要添加virtual关键字 ...

  2. C++ 学习笔记 (六) 继承- 子类与父类有同名函数,变量

    学习了类的继承,今天说一下当父类与子类中有同名函数和变量时那么程序将怎么执行.首先明确当基类和子类有同名函数或者变量时,子类依然从父类继承. 举例说明: 例程说明: 父类和子类有同名的成员 data: ...

  3. 《Java核心技术·卷Ⅰ:基础知识(原版10》学习笔记 第5章 继承

    <Java核心技术·卷Ⅰ:基础知识(原版10>学习笔记 第5章 继承 目录 <Java核心技术·卷Ⅰ:基础知识(原版10>学习笔记 第5章 继承 5.1 类.超类和子类 5.1 ...

  4. stm32学习笔记----双串口同时打开时的printf()问题

    stm32学习笔记----双串口同时打开时的printf()问题 最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其 ...

  5. JUC源码学习笔记4——原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法

    JUC源码学习笔记4--原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法 volatile的原理和内存屏障参考<Java并发编程的艺术> 原子类源码基于JDK8 ...

  6. matlab学习笔记9 高级绘图命令_1 图形对象_根对象,轴对象,用户控制对象,用户菜单对象

    一起来学matlab-matlab学习笔记9 高级绘图命令_1 图形对象_根对象,轴对象,用户控制对象,用户菜单对象 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matl ...

  7. C++使用继承时子对象的内存布局

    C++使用继承时子对象的内存布局 // */ // ]]>   C++使用继承时子对象的内存布局 Table of Contents 1 示例程序 2 对象的内存布局 1 示例程序 class ...

  8. 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响

    首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...

  9. Java学习笔记 07 接口、继承与多态

    一.类的继承 继承的好处 >>使整个程序架构具有一定的弹性,在程序中复用一些已经定义完善的类不仅可以减少软件开发周期,也可以提高软件的可维护性和可扩展性 继承的基本思想 >>基 ...

随机推荐

  1. Python学习之--数据基础

    对于Python来说,一切皆对象.包括数字.字符串.列表等,对象是由类来创建的,那对象的一个优点就是可以使用其创建类中所定义的各种方法. 查看对象/方法 1)可以在命令行中直接查看,如下: >& ...

  2. java linkedlist和arraylist添加元素时性能比较

  3. 如何做系列(3)-Java数据类型和MySql数据类型对照表

    类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述             VARCHAR L+N VARCHAR java.lang.String 12   CHAR N ...

  4. /proc/cpuinfo和/proc/meminfo来查看cpu信息与内存信息

    #一般情况下使用root或者oracle用户查都可以. # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 --查 ...

  5. svn里update以后还是有红色的感叹号怎么办

    不用那么麻烦,直接还原就行了,客户端是TortoiseSVN的话,在该文件或文件夹上点右键,选择TortoiseSVN——revert有时还原之后系统反应没那么快,还是显示红色感叹号,刷新几下就正常了 ...

  6. 深入浅出 Java Concurrency (17): 并发容器 part 2 ConcurrentMap (2)[转]

    本来想比较全面和深入的谈谈ConcurrentHashMap的,发现网上有很多对HashMap和ConcurrentHashMap分析的文章,因此本小节尽可能的分析其中的细节,少一点理论的东西,多谈谈 ...

  7. 90 k数和 II

    原题网址:https://www.lintcode.com/problem/k-sum-ii/description 描述 Given n unique integers, number k (1&l ...

  8. JEECMS自定义标签

    查看JEECMS的源代码发现开发者版本还没有类似现成的统计标签,一种解决的办法是使用现有的JEECMS标签,像这样Struts( [@cms_content_list channel=id]${tag ...

  9. js中在window.onload中写function函数产生的问题

    转载自:https://blog.csdn.net/c_p_h/article/details/63684510 今天在jsp中的form表单利用οnclick=”xxx”来监听js中一个functi ...

  10. Java内功修炼系列一工厂模式

    工厂模式是一种创建型模式,它提供了一种新的创建对象的方式,一般情况下我们都习惯用new关键字直接创建对象.有时候会遇到这种情况,我们需要根据具体的场景选择创建什么类型的对象,可能有多种类型都能选择,但 ...