C++ 类的内存分布

文章目录

  • 1 . 前言
  • 2 . 无继承,无虚函数
  • 3 . 无继承,有虚函数
  • 4 . 单一继承,无虚函数
  • 5 . 单一继承,有虚函数,虚析构
  • 6 . 多重继承
  • 7 . 菱形继承
  • 8 . 虚拟继承
  • 9 . 总结


【极客技术传送门】 : https://blog.csdn.net/Engineer_LU/article/details/135149485


1 . 前言

之前看过一些博主写的类内存排布,这边总结起来描述C++类在继承,虚函数,多继承,虚继承体现的内存排布,本文将直观简洁呈现出来

2 . 无继承,无虚函数

类代码,内存排布,如下所示 :

class Obj_A
{
private:
    char a;
    static int b;

public:
    int c;
    void func() {

    }
};

在这里插入图片描述
小结 :无继承,无虚函数的情况下
1 . 静态成员编译分布在静态区,因此静态变量b不占用类内存
2 . 成员函数编译分布在代码区,因此成员函数func()不占用类内存
3 . 类的内存排布自顶而下分布,内存对齐按照系统平台编译而定,图中32位系统,因此内存对齐按4字节


3 . 无继承,有虚函数

类代码,内存排布,如下所示 :

class Obj_A
{
private:
    char a;
    static int b;

public:
    int c;
    void func() {

    }
     virtual void func1() {

    }
};

在这里插入图片描述
小结 :无继承,有虚函数的情况下
1 . 只要类中有虚函数,编译就会生成一个 vfptr虚指针 指向虚表vftable , 其中 vfptr虚指针 根据平台所占,32位平台占用四字节


4 . 单一继承,无虚函数

类代码,内存排布,如下所示 :

class Obj_A
{
private:
    char a;
    static int b;

public:
    int c;
    void func() {

    }
};

class Obj_B : public Obj_A
{

private:
    char a;

public:
    int b;

};

在这里插入图片描述

小结 :单一继承,无虚函数的情况下
1 . 继承 Obj_A 的内存,并且追加 Obj_B 新增的内存


5 . 单一继承,有虚函数,虚析构

  1. 子类不重写的情况,如下所示 :
class Obj_A
{
private:
    char a;
    static int b;

public:
    int c;
    virtual void func() {

    }
};

class Obj_B : public Obj_A
{
private:
    char a;

public:
    int b;
};

在这里插入图片描述

  1. 子类重写的情况,如下所示 :
class Obj_A
{
private:
    char a;
    static int b;

public:
    int c;
    virtual void func() {

    }
};

class Obj_B : public Obj_A
{
private:
    char a;

public:
    int b;
    virtual void func() {

    }
};

在这里插入图片描述

小结 :单一继承,有虚函数的情况下,并且讲解为什么加虚析构
1 . 子类对应虚函数重写的情况下,子类的虚表中将覆盖父类虚函数
2 . 在多态中,当通过父类指针删除子类对象时,那么释放时是希望子类父类一起释放的,因此父类的析构设为虚函数,当父类调用时,执行的是子类的析构,这样父类就会跟着一起析构


6 . 多重继承

类代码,内存排布,如下所示 :

class Obj_A
{
    virtual ~Obj_A();
private:
    int a;

public:
    virtual void func() {

    }
};

class Obj_B
{
    virtual ~Obj_B();
private:
    int a;

public:
    void func() {

    }
};

class Obj_C : public Obj_A, public Obj_B
{

    virtual ~Obj_C();
private:
    char a;

public:
    int b;

};

在这里插入图片描述

小结 :多继承,有虚函数的情况下
1 . 子类会按顺序继承父类的内存模型
2 . 有虚函数的情况下多重继承,子类会对this指针进行偏移,如图中子类继承父类Obj_A虚表偏移值为0,而子类继承父类Obj_B虚表偏移值为-8,通过this指针偏移,子类Obj_C就可以根据继承的ObjA,ObjB虚表中相对this指针偏移,从而找到继承Obj_B的虚表,以上的-8并不是固定值,取决于Obj_A内存有多大,如Obj_A占内存24,则偏移-24


7 . 菱形继承

类代码,内存排布,如下所示 :

class Obj_A
{
    virtual ~Obj_A();
private:
    int a;

public:
    virtual void func() {

    }
};


class Obj_B : public Obj_A
{
    virtual ~Obj_B();
private:
    int a;

public:
    virtual void func() {

    }
};

class Obj_C : public Obj_A
{
    virtual ~Obj_C();
private:
    int a;

public:
    virtual void func() {

    }
};


class Obj_D : public Obj_B, public Obj_C
{

    virtual ~Obj_D();
private:
    int a;

public:
    int b;
    void func() {

    }

};

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

小结 :菱形继承,有虚函数的情况下
1 . 依然按照常规继承关系执行,只是由于Obj_B与Obj_C都继承了Obj_A,而Obj_D多重继承B与C,因此Obj_D内存模型中可以看到继承了两个Obj_A,内存按顺序排布


8 . 虚拟继承

类代码,内存排布,如下所示 :

class Obj_A
{
    virtual ~Obj_A();
private:
    int a;

public:
    virtual void func() {

    }
};


class Obj_B : virtual public Obj_A
{
    virtual ~Obj_B();
private:
    int a;

public:
    virtual void func() {

    }
};

class Obj_C : virtual public Obj_A
{
    virtual ~Obj_C();
private:
    int a;

public:
    virtual void func() {

    }
};


class Obj_D : public Obj_B, public Obj_C
{

    virtual ~Obj_D();
private:
    int a;

public:
    int b;
    void func() {

    }

};

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

小结 :虚拟继承情况下
1 . 将子类的内存放内存最前面,后面再放父类的内存,与常规内存继承反过来
2 . 产生两个虚指针,分别指向自身虚表与父类虚表
3 . 由于虚继承的父类内存模型放最后,所以前面有虚继承时,当后面有多重继承,会先把多继承的内存模型放前面,最后才放虚继承的父类,这样的好处就是不需要重复继承父类


9 . 总结

上面最后有几种情况没提到区分虚函数情况,是因为前面已经总结出有无虚函数主要体现在虚指针与虚表,所以后面直接以带虚函数来总结,全文总结了以下七种内存模型情况 :

无继承,无虚函数 的情况下 :
1 . 静态成员编译分布在静态区,因此静态变量b不占用类内存
2 . 成员函数编译分布在代码区,因此成员函数func()不占用类内存
3 . 类的内存排布自顶而下分布,内存对齐按照系统平台编译而定,图中32位系统,因此内存对齐按4字节

无继承,有虚函数 的情况下
1 . 只要类中有虚函数,编译就会生成一个 vfptr虚指针 指向虚表vftable , 其中 vfptr虚指针 根据平台所占,32位平台占用四字节

单一继承,无虚函数 的情况下
1 . 继承 Obj_A 的内存,并且追加 Obj_B 新增的内存

单一继承,有虚函数 的情况下,并且讲解为什么加虚析构
1 . 子类对应虚函数重写的情况下,子类的虚表中将覆盖父类虚函数
2 . 在多态中,当通过父类指针删除子类对象时,那么释放时是希望子类父类一起释放的,因此父类的析构设为虚函数,当父类调用时,执行的是子类的析构,这样父类就会跟着一起析构

多继承 的情况下
1 . 子类会按顺序继承父类的内存模型
2 . 有虚函数的情况下多重继承,子类会对this指针进行偏移,如图中子类继承父类Obj_A虚表偏移值为0,而子类继承父类Obj_B虚表偏移值为-8,通过this指针偏移,子类Obj_C就可以根据继承的ObjA,ObjB虚表中相对this指针偏移,从而找到继承Obj_B的虚表,以上的-8并不是固定值,取决于Obj_A内存有多大,如Obj_A占内存24,则偏移-24

菱形继承 的情况下
1 . 依然按照常规继承关系执行,只是由于Obj_B与Obj_C都继承了Obj_A,而Obj_D多重继承B与C,因此Obj_D内存模型中可以看到继承了两个Obj_A,内存按顺序排布

虚拟继承 情况下
1 . 将子类的内存放内存最前面,后面再放父类的内存,与常规内存继承反过来
2 . 产生两个虚指针,分别指向自身虚表与父类虚表
3 . 由于虚继承的父类内存模型放最后,所以前面有虚继承时,当后面有多重继承,会先把多继承的内存模型放前面,最后才放虚继承的父类,这样的好处就是不需要重复继承父类


技术交流QQ群 : 745662457

  • 问题答疑,技术交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/297418.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue框架底层

一、前端框架的由来 1、服务端渲染 sequenceDiagram 浏览器->>服务器: https://www.bilibili.com/ Note right of 服务器: 组装页面(服务端渲染) 服务器->>-浏览器: 完整页面2、前后端分离 sequenceDiagram 浏览器->>服务器: https://www.bilibili.com/ 服务…

算法基础之合并果子

合并果子 核心思想&#xff1a; 贪心 Huffman树(算法): 每次将两个最小的堆合并 然后不断向上合并 #include<iostream>#include<algorithm>#include<queue> //用小根堆实现找最小堆using namespace std;int main(){int n;cin>>n;priority_queue&l…

支持 input 函数的在线 python 运行环境 - 基于队列

支持 input 函数的在线 python 运行环境 - 基于队列 思路两次用户输入三次用户输入 实现前端使用 vue element uiWindows 环境的执行器子进程需要执行的代码 代码仓库参考 本文提供了一种方式来实现支持 input 函数&#xff0c;即支持用户输的在线 python 运行环境。效果如下图…

查询json数组

步骤一&#xff1a;创建表格 首先&#xff0c;我们需要创建一个表格来存储包含JSON对象数组的数据。可以使用以下代码创建一个名为 my_table 的表格&#xff1a; CREATE TABLE my_table (id INT PRIMARY KEY AUTO_INCREMENT,json_data JSON ); 上述代码创建了一个包含两个列的…

算法实验T15——POJ1636 Prison rearrangement

题目描述 Prison rearrangement Time Limit: 3000MSMemory Limit: 10000KTotal Submissions: 6415Accepted: 2718 Description&#xff1a; In order to lower the risk of riots and escape attempts, the boards of two nearby prisons of equal prisoner capacity, have dec…

计算机毕业设计 SpringBoot的中小型制造企业质量管理系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Kafka安全认证机制详解之SASL_PLAIN

一、概述 官方文档&#xff1a; https://kafka.apache.org/documentation/#security 在官方文档中&#xff0c;kafka有五种加密认证方式&#xff0c;分别如下&#xff1a; SSL&#xff1a;用于测试环境SASL/GSSAPI (Kerberos) &#xff1a;使用kerberos认证&#xff0c;密码是…

Ubuntu 本地部署 ChatGPT-Next-Web

Ubuntu 本地部署 ChatGPT-Next-Web 文章目录 Ubuntu 本地部署 ChatGPT-Next-Web ChatGPT-Next-Web 项目地址&#xff1a;https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web 本文主要演示如何在 Ubuntu 本地&#xff08;默认是端口 3000&#xff09;部署 ChatGPT-Next-Web&am…

差分约束算法

差分约束 差分约束系统包含 m m m个涉及 n n n个变量的差额限制条件&#xff0c;这些差额限制条件每个都是形式为 x i − x j ≤ b ∈ [ 1 , m ] x_i-x_j\leq b_{\in[1,m]} xi​−xj​≤b∈[1,m]​的简单线性不等式。 通常我们要求解出一组可行解。 最短路差分约束 如果我们…

ejs默认配置 造成原型链污染

文章目录 ejs默认配置 造成原型链污染漏洞背景漏洞分析漏洞利用 例题 [SEETF 2023]Express JavaScript Security ejs默认配置 造成原型链污染 参考文章 漏洞背景 EJS维护者对原型链污染的问题有着很好的理解&#xff0c;并使用非常安全的函数清理他们创建的每个对象 利用Re…

苹果macOS 14.3开发者预览版Beta 2发布 修复API会意外失败的问题

1 月 4 日消息&#xff0c;苹果向 Mac 电脑用户推送了 macOS 14.3 开发者预览版 Beta 2 更新&#xff08;内部版本号&#xff1a;23D5043d&#xff09;&#xff0c;本次更新距离上次发布隔了 22 天。 macOS Sonoma 14.3 Beta 2 主要以修复 BUG、提高安全性为主。根据苹果官方更…

VS+QT五子棋游戏开发

1、首先安装好VS软件和QT库&#xff0c;将其配置好&#xff0c;具体不在此展开说明。 2、文件结构如下图&#xff1a; 3、绘制棋盘代码&#xff0c;如下&#xff1a; void Qwzq::paintEvent(QPaintEvent* event) {QPainter painter(this);painter.setRenderHint(QPainter::An…

线性代数第一课+第二课总结

第一课 第一课是简单的行列式计算&#xff0c;主要就是要把左下角的数字全部转换为0&#xff0c;通过减去其他行的式子即可实现&#xff0c;最后把对角线的所有数字相乘&#xff0c;得到的结果是最后行列式的答案 第二课 例题1 硬算理论上其实也是可行的&#xff0c;但是使…

遇见狂神说 Spring学习笔记(完整笔记+代码)

简介 Spring是一个开源的免费的框架&#xff08;容器&#xff09;Spring是一个轻量级的、非入侵式的框架控制反转(IOC&#xff09;&#xff0c;面向切面编程 (AOP)支持事务的处理&#xff0c;支持对框架进行整合 Spring就是一个轻量级的控制反转&#xff08;IOC&#xff09;和…

亚马逊云科技基于 listmonk 的电子邮件营销解决方案

本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道。 背景 电子邮件营销&#xff08;EDM&#xff09;在广告、电商、供应链物流等行业应用…

Linux操作系统基础(10):Linux的特殊权限

1. 特殊权限是什么 在Linux中&#xff0c;特殊权限是指针对文件或目录的特殊权限设置&#xff0c;包括SetUID、SetGID和Sticky Bit。 SetUID&#xff08;Set User ID&#xff09;&#xff1a; 当一个可执行文件被设置了SetUID权限后&#xff0c;当任何用户执行该文件时&#x…

UI5与后端的文件交互(二)

文章目录 前言一、开发Action1. 创建Structure2. BEDF添加Action3. class中实现Action 二、修改UI5 项目1. 添加一个按钮2. 定义事件函数 三、测试及解析1. 测试2. js中提取到的excel流数据3. 后端解析 前言 这系列文章详细记录在Fiori应用中如何在前端和后端之间使用文件进行…

数字图像处理(图像灰度变换、图像直方图及均衡、图像中值滤波、图像空域锐化增强、图像频域滤波)

数字图像处理&#xff08;图像灰度变换、图像直方图及均衡、图像中值滤波、图像空域锐化增强、图像频域滤波&#xff09; 目录 1 图像灰度变换 1.1 灰度线性变换 1.2 图像二值化 1.3 负象变换 1.4 灰度非线性变换 1.5 程序设计流程图 2 图像直方图及均衡 2.1 直方图 2…

了解单元测试

一&#xff0c;测试分类 1.1 E2E测试&#xff08;end to end端到端测试&#xff09; 属于黑盒测试。 主要通过测试框架&#xff0c;站在用户测试人员的角度&#xff0c;模拟用户的操作进行页面功能的验证&#xff0c;不管内部实现机制&#xff0c;完全模拟浏览器的行为。&am…

Pytest——Fixture夹具的使用

一、什么是Fixture 在测试开展的过程中&#xff0c;会需要考虑到测试前的准备工作&#xff0c;以及测试后的释放操作行为。这些在Pytest中&#xff0c;会通过Fixture的方式来实现。如果说在运行pytest的测试用例的时候&#xff0c;需要调用一些数据来实现测试行为&#xff0c;…