C++继承派生以及虚基类的内存分布

news2025/7/19 10:13:38

C++中类有3种权限:public、protected、private。(本文为《直击招聘》的笔记总结)。

如果没有指明默认为private,定义class A如下

class A 
{
    int x;
public:
    void displaya() {
        cout << "A::x:" << &x << endl;
    }
};

定义B、C类都继承A,D继承BC

class B: public A
{
    int y1, y2;
public:
    void displayb() {
        cout << "B::y1:" << &y1 << "B::y2:" << &y2 << endl;
    }
};
class C: public A
{
    int z;
public:
    void displayc() {
        cout << "C::z:" << &z << endl;
    }
};
class D:public B, public C
{
    int m;
public:
    void displayd() {
        B::displaya();
        displayb();
        C::displaya();
        displayc();
        cout << "D::m:" << &m << endl;
    }
};

可以打印下sizeof(D),D中只有一个int m,但是D的大小竟然是24字节,这其中必定和继承有关。

很容易想到继承的父类都分了一个内存,但是按照上图,就算把A的x也算进去一共也有只有5个int呀。很多人心里都有了猜测,为了验证:

不妨打印一下sizeof(B),结果是12,打印一下sizeof(C),是8.

这就破案了,x出现了2次。

出现这样的原因是:派生类的对象中存放着所有基类的非静态数据成员,其中包括私有成员(不管能不能访问)内存都是占着的。

顺便提一嘴,空类也是有一个字节占位的,非空类的大小并不是简单的相加,而是要按照内存对齐原则,因为我们这里全是int所以就不用考虑。

int main()
{
    D d;
    cout << "d:" << &d << endl;
    d.displayd();
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    cout << sizeof(C) << endl;
    cout << sizeof(D) << endl;
    return 0;
}

看上面代码输出会发现d对象的地址就是B中A::x的地址,而不是C中A::x的地址,这是因为我们定义的时候是class D:public B, public C。


虚基类

上面说到就算是隐藏的变量,也要单独为他开辟内存,对于复杂的类层次中存在多次继承的问题,可以用虚继承。

虚继承和继承的语法差别就是多了一个virtual

但是内存里放的东西差别还是比较大。

对于这样一个层次结构,虚线表示虚继承,sizeof(C)会是16,也就是4个字节大小,这里可能就蒙蔽了,三个加起来也没有重复的(比如上面的A的x就出现了两次),怎么会是4字节大小呢。

说明他并不是这样存储的。

对于C类的一个对象,在最开头存放一个虚基类表的地址,外接一个虚基类表,里面的数据表示相对偏移量,0x8表示相对偏移两个字节,AB都是虚基类,只需要在虚基类表中添加进去就可以。所以不管有多少个虚基类,只要一个vbptr和虚基类表就可以,在里面添加上虚基类的地址,C虚继承AB,加上自己的一个int和一个虚基类表指针就是4个字节。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

理解进程、通过调用 fork 函数创建进程

文章目录1.理解进程1.1 CPU核的个数与进程数1.2 进程 ID2.通过调用 fork 函数创建进程2.1 fork.c1.理解进程 进程&#xff08;Process&#xff09;&#xff0c;其定义如下&#xff1a;“占用内存空间的正在运行的程序”。 假如各位从网上下载了 LBreakout 游戏并安装到硬盘。…

CS项目实训-Java 银行ATM机

摘 要 本次课程设计主要目的是培养我们面向对象软件开发的思维&#xff0c;初步了解软件开发的一般流程。提高编程的实际动手能力并增强大家对面向对象的了解。这次课程设计的主要内容是开发一个应用程序&#xff0c;我们小组设计的ATM柜员机&#xff0c;它主要是由各个indows窗…

05 | 如何安全、快速地接入OAuth 2.0?

05 | 如何安全、快速地接入OAuth 2.0&#xff1f; 构建第三方软件应用 第一点&#xff0c;注册信息 小兔软件的研发人员提前登录到京东商家开放平台进行手动注册&#xff0c;以便后续使用这些注册的相关信息来请求访问令牌。兔软件需要先拥有自己的 app_id 和 app_serect 等信…

联想笔记本电脑开机后一直转圈无法启动怎么办?

联想笔记本电脑开机后一直转圈无法启动怎么办&#xff1f;在正常开启电脑的过程中&#xff0c;系统进入到加载页面&#xff0c;但是却一直无法正常的启动。进行系统的重新启动依然是无法正常的使用。遇到这个情况需要进行系统的重置。接下来我们来看看详细的解决方法分享吧。 准…

实现用户操作日志记录

Java记录操作日志 java自带的日志框架是java.util.logging&#xff08;JUL&#xff09;&#xff0c;从JDK1.4&#xff08;2002&#xff09;开始捆绑在JDK中。可以使用JUL来记录操作日志。以下是使用JUL记录事务的示例&#xff1a; // java.util.logging java.util.logging.Lo…

网分线缆测试和dc-block

今天的好苹果和坏苹果 好苹果&#xff1a;是校准件和网分都是好的&#xff0c;又给了我一次复盘的机会 网分测试线缆&#xff1a; 1.网分直接复位&#xff0c;如果网分复位是校准状态&#xff0c;且解的是精密转接头&#xff0c;BNC的&#xff0c;可以不校准&#xff0c;结果差…

【高中数学教资】教案设计通用模板

前言 本文针对的是高中数学教师资格证笔试中最后的大题——教案设计&#xff08;含设计意图&#xff0c;文末有2022下半年高中数学教资教案设计大题&#xff09;。并附上高中数学404教资考点大纲&#xff0c;还有在学习中发现的一些可以免费学习网站推荐。 一、高中数学404考…

List系列集合

一. List集合特点、特有API List的实现类的底层原理 ArrayList底层是基于数组实现的&#xff1a;根据索引定位元素快&#xff0c;增删相对慢。LinkedList底层基于双链表实现的&#xff1a;查询元素慢&#xff0c;增删首尾元素是非常快的。public class ListDemo01 {public sta…

SerDes---CDR技术

1、为什么需要CDR 时钟数据恢复主要完成两个工作&#xff0c;一个是时钟恢复&#xff0c;一个是数据重定时&#xff0c;也就是数据的恢复。时钟恢复主要是从接收到的 NRZ&#xff08;非归零码&#xff09;码中将嵌入在数据中的时钟信息提取出来。 2、CDR种类 PLL-Based CDROve…

【信号与系统笔记】第一章 绪论

1.1信号传输系统 信息传输的任务 将带有信息的信号&#xff0c;通过某种系统由发送者传送给接收者。 通信系统的组成 转换器&#xff1a;把消息转换为电信号或者把电信号还原成消息信道&#xff1a;信号传输的通道&#xff0c;广义上来说。发射机和接收机也可以是信道的一部分…

【RabbitMQ】Producer之publisher confirm、transaction - 基于AMQP 0-9-1(二)

上篇文章主要介绍Producer的mandatory参数&#xff0c;备份队列和TTL的内容&#xff0c;这篇文章讲继续介绍Producer端的开发&#xff0c;主要包括发布方确认和事务机制。 发布方确认 消息持久化机制可以保证应服务器出现异常导致消息丢失的问题&#xff0c;但是Producer将消…

线程池ThreadPoolExecutor,从0到0.6

ThreadPoolExecutor是JDK提供的在java.util.concurrent包中的一个用于创建线程池的工具类。 一、ThreadPoolExecutor的7个参数 corePoolSize&#xff1a;核心线程数&#xff0c;线程池中保留的最小的线程数量&#xff0c;即使它们是空闲的也不会被销毁&#xff0c;除非allowCor…

Modbus转profinet网关连接1200PLC在博图组态与驱动器通讯程序案例

本案例给大家介绍由兴达易控modbus转profinet网关连接1200PLC在博图软件无需编程&#xff0c;实现1200Profinet转modbus与驱动器通讯的程序案例 硬件连接&#xff1a;1200PLC一台&#xff1b;英威腾DA180系列驱动器一台&#xff1b;兴达易控modbus转profinet网关一台 下面就是…

【Git】拉取 Pull Requests 测试的两种方法

文章目录前言参考目录方法说明方法一&#xff1a;直接拉取方法二&#xff1a;使用 diff 文件2.1、保存 diff 文件2.2、新建分支并执行文件前言 最近有参与到框架帮忙进行简单的 Pull Requests&#xff08;以下简称 PR&#xff09; 测试&#xff0c;因为也是第一次接触到这种操…

代码随想录 动态规划||01背包理论 416

Day3601背包理论基础01背包有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来…

Java学习笔记 --- Servlet(1)

一、Servlet技术 1、Servlet基本介绍 1、Servlet 是 JavaEE 规范之一。规范就是接口 2、Servlet 就 JavaWeb 三大组件之一。三大组件分别是&#xff1a;Servlet 程序、Filter 过滤器、Listener 监听器。 3、Servlet 是运行在服务器上的一个 java 小程序&#xff0c;它可以…

院士交锋,专家论道|NLP大模型技术与应用十大挑战,剑指AI未来

2023年2月24日下午&#xff0c;第四届OpenI/O启智开发者大会NLP大模型分论坛在深圳人才研修院隆重举办。NLP大模型论坛会议现场众多NLP领域顶级专家学者与多家国产NLP大模型开发团队汇聚一堂&#xff0c;学术界与产业界破圈交流&#xff0c;激荡尖端思想、分享前沿动态&#xf…

Linux学习第二十二节-网卡IP设置

1.修改网卡IP地址 方式一&#xff1a;通过修改网卡配置文件修改 网卡配置文件位置&#xff1a; /etc/sysconfig/network-scripts/网卡名 #ifconfig 表示用于显示和设置网卡的参数 #ip addr 表示用于显示和设置网卡的参数 #systemctl restart network 表示重启网络 …

Spark Join大小表

Spark Join大小表无法广播过滤后大小表数据分布均匀大小表 : 大小表尺寸相差 3 倍以上 Join 优先考虑 BHJ小表的数据量 > 广播阈值时&#xff0c;优先考虑 SHJ 无法广播 大表 100GB、小表 10GB&#xff0c;都远超广播变量阈值 当小表的尺寸 > 8GB时&#xff0c;创建广…

剑指-Offer-30-包含min函数的栈

剑指 Offer 30.包含min函数的栈 题目描述&#xff1a; 定义栈的数据结构&#xff0c;请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中&#xff0c;调用 min、push 及 pop 的时间复杂度都是 O(1)。 示例&#xff1a; MinStack minStack new MinStack(); minSt…