C++继承内存对象模型

2023-11-08

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

         对这篇文章做了做总结。本文的大部分内容来自于这篇文章中的总结http://blog.csdn.net/haoel/article/details/3081328C++ 对象的内存布局

           分为四种情况:

1.单继承

2.多继承(不含钻石继承)

3.非虚继承的钻石继承

4.虚继承的钻石继承

注:下面所有类中的函数都是虚函数。

1.单继承

单继承体系如下:


GrandChild对象的内存布局


可见以下几个方面:

1)虚函数表在最前面的位置。

2)成员变量根据其继承和声明顺序依次放在后面。

3)在单一的继承中,被overwrite的虚函数在虚函数表中得到了更新。

2.多继承

多继承的体系如下:


Derive对象的内存布局如下:


我们可以看到:

1) 每个父类都有自己的虚表。

2)  子类的成员函数被放到了第一个父类的表中。

3) 内存布局中,其父类布局依次按声明顺序排列。

4) 每个父类的虚表中的f()函数都被overwrite成了子类的f()。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。


出现钻石继承的虚继承的时候,虚基类在子类中只有一份。

出现钻石继承的非虚继承的时候,虚基类在每个子类中都有一份。

3.非虚继承的钻石继承

继承体系如下:


D的内存布局如下:


红色的部分就是重复的部分,就会造成二义性


4.虚继承的钻石继承(虚继承就是解决钻石继承问题的,如果不存在钻石继承,就不用虚继承)

继承体系如下:(红色专门标准虚继承)


D的内存布局如下:

可以看出,少了重合的部分。但是,代价是增加了一个虚函数指针

   

关于虚继承,多写一点儿

http://blog.csdn.net/xsh_123321/article/details/5956289


1.为什么需要虚继承

如下图所示如果访问Der::Fun or Der::m_nValue就会带来二义性,无法确定是调用Base1的还是Base2的,所以为了解决多重继承情况下成员访问的二义性,引入了虚继承机制。(说白了,虚继承就是共享继承,“共享”)


2.虚继承实现

在虚继承下,Der通过共享虚基类SuperBase来避免二义性,在Base1,Base2中分别保存虚基类指针,Der继承Base1,Base2,包含Base1, Base2的虚基类指针,并指向同一块内存区,这样Der便可以间接存取虚基类的成员,如下图所示:

3.不同编译器实现方式

不同编译器对间接存取的方法不同,以下以GCC和VC为例,均采用以下代码进行实验:

class SuperBase
{
public:
    int m_nValue;
    void Fun(){cout<<"SuperBase1"<<endl;}
    virtual ~SuperBase(){}
};
class Base1:  virtual public SuperBase
{
public:
virtual ~ Base1(){}
};
class Base2:  virtual public SuperBase
{
public:
virtual ~ Base2(){}
};
class Der:public Base1, public Base2
{
public:
virtual ~ Der(){}
};
void main()
{
cout<<sizeof(SuperBase)<<sizeof(Base1)<<sizeof(Base2)<<sizeof(Der)<<endl;
}

1) GCC中结果为8, 12, 12, 16

解析:sizeof(SuperBase) = sizeof(int) + 虚函数表指针

sizeof(Base1) = sizeof(Base2) = sizeof(int) + 虚函数指针 + 虚基类指针

sizeof(Der) = sizeof(int) + Base1中虚基类指针 + Base2虚基类指针 + 虚函数指针 

GCC共享虚函数表指针,也就是说父类如果已经有虚函数表指针,那么子类中共享父类的虚函数表指针空间,不在占用额外的空间,这一点与VC不同,VC在虚继承情况下,不共享父类虚函数表指针,详见如下。

2)VC中结果为:8, 16, 16, 24

解析:sizeof(SuperBase) = sizeof(int) + 虚函数表指针

sizeof(Base1) = sizeof(Base2) = sizeof(int) + SuperBase虚函数指针 + 虚基类指针 + 自身虚函数指针

sizeof(Der) = sizeof(int) + Base1中虚基类指针 + Base2中虚基类指针 + Base1虚函数指针 + Base2虚函数指针 + 自身虚函数指针

如果去掉虚继承,结果将和GCC结果一样,A,B,C都是8,D为16,原因就是VC的编译器对于非虚继承,父类和子类是共享虚函数表指针的。




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++继承内存对象模型 的相关文章

随机推荐

  • Springboot修改内置Tomcat版本

    背景 Tomcat的安全漏洞需要升级版本进行解决 如 9 0 63 gt 9 0 75 1 Pom文件Springboot的依赖配置项 2 Ctrl 右键点击红色框选 3 全局搜索 修改 修改数值 启动测试
  • C++实现——string的所有操作

    C 中string的操作 Constructors 构造函数 用于字符串初始化 Operators 操作符 用于字符串比较和赋值 append 在字符串的末尾添加文本 assign 为字符串赋新值 at 按给定索引值返回字符 begin 返
  • 基于python实现的CS通信和P2P通信

    实验要求 C S通信实现要求 两台计算机分别模拟服务器 客户端 通过编程实现服务器端 客户端程序Socket Client 服务器端程序监听客户端向服务器端发出的请求 并返回数据给客户端 不采用方式 自定义通信协议 传输文件要足够大 例如
  • Python GUI: PyCahrm结合Pyqt5开发图形化界面 详细步骤 踩坑!

    1 下载安装pythonPython官网下载地址 注意 1 1 Python版本选择并不是越新越好 后面会提到 我安装的版本是 V3 5 4 64位 1 2 安装的时候一定要勾选pip和add python to path 自动添加到环境变
  • 清华大佬耗时36个小时,终于整理出来了一份Python自学计划,学不会退出IT界

    在人工智能的风口 Python这门胶水语言越来越火 很多小伙伴也开始学习Python 但是没有一份合适的学习规划怎么能行 今天特意为大家整理了一份Python自学计划 希望可以帮助到处在迷茫期的你们 文末获取o 这份自学计划是我精心整理的
  • React+AntDesign开发完整的考勤系统前端页面(一)

    一 项目准备工作 1 开发环境准备 准备好Visual Studio Code前端开发工具 下载并安装Node js 2 项目准备 本次项目使用umi脚手架的方式创建 1 打开开发工具打开项目文件夹并新建终端在终端里面输入命令 npm i
  • 【概率论与数理统计】猴博士 笔记 p17-20 一、二维连续型:已知F,求f;已知f,求f

    一维连续型已知F 求f 题型 步骤 f是F的导数 对F求导即可得到f 例1 解 例2 解 一维连续型已知f 求f 题型 已知f x 求f y 步骤 注意 要满足要求 Y g X 满足单增或单减才能用公式法 看起来有点抽象 我们看一道例题 此
  • GAMES101 作业3(附三角形重心坐标,Blinn-Phong光照模型及法线贴图推导)

    目录 写在前面 第一题 三角形重心坐标 第二题 Blinn Phong光照模型 第三题 纹理贴图 第四题 凹凸贴图实现及法线贴图推导 第五题 位移贴图 写在前面 main 函数中 std function
  • FedDG: Federated Domain Generalization on Medical Image Segmentation via Episodic Learning

    FedDG Federated Domain Generalization on Medical Image Segmentation via Episodic Learning in Continuous Frequency Space
  • 数据库锁表的查询和处理

    如果遇到数据库锁表 通常需要用如下方法处理 查看表的partnum情况 oncheck pt shjz mzb baf01 grep i partnum 这个里面包含了多个分区的partnum 也包含了索引的partnum Partitio
  • Windows安装和配置VCenter

    Vcenter的环境搭建和配置 Vcenter简介 Vcenter一般指 VMware vCenter Server VMware vCenterServer 提供了一个可伸缩 可扩展的平台 为 虚拟化管理奠定了基础 VMware vCen
  • 射线与AABB型包围盒相交算法

    基础知识 AABB包围盒 也叫轴对称包围盒 意思就是它的六个面总是分别平行XYZ三个轴的 相交计算原理 计算射线与包围盒每个面的平面的交点 计算这个点是否在包围盒面的范围 在就是相交 不在就是没有相交 图解 用个2D图形简单讲解一下 首先从
  • C++ 一些学习笔记(十一)类和对象-继承

    C 一些学习笔记 十一 类和对象 继承 主要是针对之前学习C的时候一些知识点的遗漏的补充 还有一些我自己觉得比较重要的地方 本文章的主要内容是关于继承 1 继承的基本语法 2 继承方式 3 继承中的对象模型 4 继承中的构造和析构顺序 5
  • 虚拟化技术调研

    虚拟化技术调研 容器 虚拟化技术 容器是一种轻量级虚拟化技术 它可以在一台宿主机上共享内核 并且在运行应用程序时具有独立的文件系统空间 网络空间 进程空间和用户空间 常见的容器技术有Docker和LXC KVM虚拟化技术 KVM是一种全虚拟
  • Nginx反向代理服务器搭建(超详细)

    一 简介 Nginx engine x 是一个高性能的Web服务器和反向代理服务器 也可以作为邮件代理服务器 反向代理 Reverse Proxy 方式是指以代理服务器来接受internet上的连接请求 然后将请求转发给内部网络上的服务器
  • 前端map传给后端接收

    前端let map new Map map set 1 1 map set 2 2 map set 3 3 map转obj let obj Object create null for let k v of map obj k v ajax
  • sql实现多字段去重

    sql实现多字段去重 且返回所有字段 1 主要思想 根据需求去重的字段进行分组 获取id 在联合查询 2 主要代码 SELECT from table A where id in SELECT max id from table A gro
  • 机器学习框架Ray -- 2.4 基于Ray的Fashion Minst数据集识别

    1 概述 使用 Ray 和 Ray Train 可以在多个 worker 上分发训练任务 从而加速整个训练过程 每个 worker 都在独立的数据子集上训练相同的神经网络结构 在训练过程中 所有 worker 共享并更新同一个神经网络的参数
  • Qt通讯 - MQTT

    部署 1 perl 要安装perl 可以参考perl 2 编译qt的MQTT源码 Qt MQTT SOURCECODE EMQX QMQTT 编译中可能遇到的问题 error
  • C++继承内存对象模型

    最近研究了一下 C 继承的内存对象模型 主要是读了读http blog csdn net haoel article details 3081328 C 对象的内存布局 很推荐这篇文章 对这篇文章做了做总结 本文的大部分内容来自于这篇文章中