C++ 详谈继承体系下的构造函数和析构函数

咱们一起学C++ 第二百二十四篇之C++析构函数与虚拟析构函数的深度探索 大家好!C++学习的道路充满挑战,但每一次深入了解新的知识点,都像是解锁了新技能,让我们离编程高手又近了一步。今天咱们来探索C++中析构函数和虚拟析构函数的奥秘,希望能和大家一起进步,收获满满的知识! 阅读详情

前言

前面呢, 我们说了C++中实现多态的原理, 其中也说了, 虚函数表和虚函数指针的创建时机, C++ 详谈多态实现原理-优快云博客 , 这一节呢, 我们会说说在C++中继承体系下的另一个知识点, 那就是: 继承体系下的构造函数和析构函数~~, 主要围绕两个问题: 执行顺序? 虚析构函数的作用? 

继承体系下的构造函数和析构函数的执行顺序

首先我们用一句话来概括, 之后再做详细解释: 继承下, 构造函数按照依赖链(孩子依赖父亲), 从上往下构造, 析构函数按照依赖链, 从下向上析构.

我们从两个角度来探讨, 单继承 和 多继承.

单继承

我们现在在前面代码的基础上添加两个类, Base1和Drive1, Base1作为Base类中的成员变量, Drive1作为Drive中的成员变量, 我们可以设想一些这个情况下的调用顺序, 构造Drive之前要先构造Base 和 构造Drive1, 构造Base之前要先构造Base1, 所以其构造顺序应该是: Base1, Base, Drive1, Drive, 其析构顺序应该是: Drive, Drive1, Base, Base1

#include <iostream>

using namespace std;

class Base1
{
public:
	Base1()
	{
		cout << "Base1 construction" << endl;
	}
	~Base1()
	{
		cout << "Base1 destruction" << endl;
	}
};
class Drive1
{
public:
	Drive1()
	{
		cout << "Drive1 construction" << endl;
	}
	~Drive1()
	{
		cout << "Drive1 destruction" << endl;
	}
};
class Base
{
public:
	Base()
	{
		cout << "Base construction" << endl;
	}
	~Base()
	{
		cout << "Base destruction" << endl;
	}
private:
	Base1 b1;
};
class Drive : public Base
{
public:
	Drive()
	{
		cout << "Drive construction" << endl;
	}
	~Drive()
	{
		cout << "Drive destruction" << endl;
	}
private:
	Drive1 d1;
};
int main()
{
	Drive d;
	cout << "------------------" << endl;
	return 0;
}

成员类按照顺序构造, 优先于类的构造, 按照相反顺序析构. 

多继承

现在, 代码有 一个MBase1和MBase2, 一个MDrive多继承自MBase1和MBase2, 并且MDrive中还有成员变量, MDrive1和MDrive2类型的变量, 构造顺序是继承的顺序

#include <iostream>

using namespace std;

class MBase1
{
public:
	MBase1()
	{
		cout << "MBase1 construction" << endl;
	}
	~MBase()
	{
		cout << "MBase1 destruction" << endl;
	}
};
class MBase2
{
public:
	MBase2()
	{
		cout << "MBase2 construction" << endl;
	}
	~MBase2()
	{
		cout << "MBase2 destruction" << endl;
	}
};
class MDrive1
{
public:
	MDrive1()
	{
		cout << "MDrive1construction" << endl;
	}
	~MDrive1()
	{
		cout << "MDrive1destruction" << endl;
	}
};
class MDrive2
{
public:
	MDrive2()
	{
		cout << "MDrive2 construction" << endl;
	}
	~MBase()
	{
		cout << "MDrive2 destruction" << endl;
	}
};
class MDrive : public MBase1, MBase2
{
public:
	MDrive()
	{
		cout << "MDrive construction" << endl;
	}
	~MDrive()
	{
		cout << "MDrive destruction" << endl;
	}
private:
	MDrive1 md1;
    MDrive2 md2;
};
int main()
{
	MDrive md;
	cout << "------------------" << endl;
	return 0;
}

多继承中, 除了前面单继承中的构造顺序, 基类是声明顺序构造, 相反顺序析构, 上面这一段代码就是, 先构造MBase1, 再构造MBase2, 再构造MDrive1和MDirve2, 最后构造MDrive.

虚析构函数的作用

作用: 在继承下, 为了使子类析构函数能够得到正常调用, 需要将基类的析构函数设置为虚析构函数.

 C++中, 当一个类要被作为基类被继承是, 应该将这个基类的析构函数手动设置为虚析构函数, 之前说过, C++中如果一个方法是virtual修饰的, 那么在子类继承之后重写这个方法, 也是virtual修饰的, C++会将所有的析构函数名称修改成同一个.

这样如果父类的析构函数是虚析构函数, 子类中一定是有同名的虚的析构函数, 这样经过两次vptr的赋值, 就能正常的调用到虚构造函数了~~

永久关闭Windows更新的5种方法 很多家用电脑,如果系统自动更新的话,会变得越来越卡顿,且硬件型号兼容也并不完美。那么我们该如何彻底关闭Win11的自动更新呢?以下准备了5种方法,您可以根据自身实际情况选择合适的方法! 阅读详情

相关推荐

H3C设备VRF配置实战:5步搞定多业务网络隔离(附排错技巧)

本文详细介绍了在H3C设备上配置VRF(虚拟路由转发)实现多业务网络隔离的实战方法。通过五步配置流程,从创建VPN-instance、绑定接口到配置独立路由表,帮助网络工程师在单台设备上构建逻辑隔离的企业级网络,并分享了高级路由配置与常见排错技巧。

gold8的专栏 936

c++ 构造函数与析构函数

本文参考,仅作笔记用。

qq_44691564的博客 1099

EDA开源仿真工具verilator入门4:访问函数介绍

访问函数(Visitor Function)是verilator算法实现的主要工作方式之一,本节将介绍一下访问函数。

fangfanglovezhou的博客 1075

【C/C++ 构造函数和析构函数可以重载吗?】

C++中构造函数与析构函数的重载规则存在本质差异:构造函数允许重载,通过不同参数列表实现多种初始化方式;而析构函数禁止重载,每个类只能有一个无参数的析构函数。这种差异源于对象创建时的灵活性需求与销毁时的确定性要求。构造函数重载支持委托构造、隐式转换等特性,而析构函数的唯一性确保了资源释放的统一性和继承体系的安全性。最佳实践包括:合理使用explicit构造函数、委托构造,以及为基类声明虚析构函数。理解这些差异是掌握C++对象生命周期管理的关键。

一起学习进步! 1225

计数译码驱动显示电路实验报告_京东方G0A电路、阵列基板、显示 装置及驱动方法广州威彩...

图1、实施例二所述的选择子单元的结构示意图图2、实施例四所述的GOA电路结构示意图图3、实施例七所述的阵列基板的局部结构示意图图4、实施例所述的极性反转驱动方法的第一场的各信号时序图图5、实施例所述的极性反转驱动方法的第二场的各信号时序图图6、实施例所述的极性反转驱动方法的第三场的各信号时序图图7、实施例所述的极性反转驱动方法的第四场的各信号时序图图8、为图4所示时序下,实施例八所述显示...

weixin_35696112的博客 924

嵌入式开发必备:手把手教你用DB-9连接器搞定RS-232串口通信(附万用表测试技巧)

本文详细解析了嵌入式开发中RS-232串口通信的硬件连接核心。从DB-9连接器的引脚定义入手,深入讲解DTE与DCE设备角色,明确直连线与交叉线的选择法则,并重点分享了使用万用表进行线缆连通性测试、电压测量及故障诊断的实战技巧,帮助开发者彻底掌握串口通信的硬件连接与排查方法。

tgb345678的博客 1165

C++ 构造函数和析构函数与virtual关键字

一、构造函数 1.构造函数任何时候都不可以声明为虚函数,原因如下:1)虚函数的调用军需通过虚函数表vtable来调用,虚函数表是存储在内存空间的,在调用构造函数前,对象还未被实力化,也就没有该对象的内存空间,也无法找到虚函数表;2)虚函数表实在对象构造之后才建立的,所以构造函数不可能是函数。2.不能在构造函数内调用虚函数,原因如下:假设有个class继承体系,如下代码,在该base class 的

luoxue720的博客 4262

基于STM32H750的便携式双通道示波器与信号发生器AFE设计

示波器和信号发生器是电子测量与嵌入式系统调试的基础仪器,其核心在于模拟前端(AFE)对宽动态范围、高精度采样与低失真输出的协同实现。原理上需兼顾输入信号调理(衰减/放大/偏置)、ADC/DAC接口匹配、触发同步及电源完整性设计。技术价值体现在以低成本器件达成±15V输入/±10V输出、16位等效采样精度与85kHz带宽的工程平衡。典型应用场景包括电机驱动波形观测、传感器信号验证、电源环路测试及通信电平分析。本方案聚焦STM32H750平台,深度融合硬件拓扑与片上资源特性,为嵌入式教学与原型开发提供可复现、易

weixin_35755188的博客 107

cpp——类——析构函数

概述 析构函数特点: 函数名为“~类名”,用来标记和识别析构函数 没有返回值,析构函数是对自身的销毁行为,返回值无意义,因为没有返回值的接收者 形参列表为空,所以析构函数没有重载,唯一的 构造函数VS析构函数: 构造函数是对自身的初始化,生成(定义)对象时自动调用 析构函数是对自身的销毁,销毁对象时自动调用 辅助类 class CAnimal { public: CAnimal() : mGroup(0) { cout << "CAnimal()" << endl;

mardax的专栏 3000

如何打开本地网络的防火墙端口(Windows版)解决ConnectionRefusedError: [WinError 10061] 由于目标计算机积极拒绝,无法连接。问题

ConnectionRefusedError: [WinError 10061] 由于目标计算机积极拒绝,无法连接。 最开始在遇到这个报错的时候十分不解,后来经过思考,有可能是服务器端口占用,或者并没有放行。因此搜查问题的关键是要先去排查问题。 在搜索栏输入控制面板 选择防火墙 选择开关 保证这些选项是开着的 选择高级设置 新建规则 创建协议端口 选择端口 允许连接 点击下一步 创建规则后点击下一步(后命名) 选择任意端口ALL即可 问题排查完毕!socket创建网络通信时,有读者

weixin_46900108的博客 9万+

how2heap 深入学习(1)

how2heap glibc 2.23学习

CoLin的pwn小屋 3179

构造函数和析构函数能否声明为虚函数?

构造函数不能声明为虚函数,析构函数可以声明为虚函数,而且有时是必须声明为虚函数。 不建议在构造函数和析构函数里面调用虚函数。 构造函数不能声明为虚函数的原因是: 解释一:所谓虚函数就是多态情况下只执行一个。而从继承的概念来讲,总是要先构造父类对象,然后才能是子类对象。如果构造函数设为虚函数,那么当你在构造父类的构造函数时就不得不显示的调用构造。还有一个原因就是为了防错,试想如果你

gavin0123的专栏 1435

【DeepSeek开发入门】DeepSeek API 开发初体验

在人工智能蓬勃发展的时代,DeepSeek作为一款功能强大的AI大模型,为开发者提供了丰富的接口和便捷的开发体验。本文将基于DeepSeek的几个关键接口,带你快速入门,开启DeepSeek开发的探索之旅。通过本文,你已经初步了解了DeepSeek开发中几个重要接口的使用方法,包括列出模型、对话补全和查询余额接口,以及开发过程中的常见问题及解决办法。这是你踏入DeepSeek开发领域的第一步。在后续的学习中,你可以深入研究模型的参数调优,探索不同模型在各种场景下的应用,如利用模型实现更复杂的推理对话功能。

寻道AI,探索AI无限可能! 2755

继承中构造函数和析构函数地调用顺序

现在,有三个类,类的定义如下 class CA { public:  CA(){cout       ~CA(){cout }; class CB:public CA { public:  CB(){cout    ~CB(){cout }; class CC:public CB { public:  CC(){cout    ~CC()

把握自己。 6584

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++ Primer13 继承中类的作用域 继承体系的构造函数和拷贝控制

…

weixin_42289038的博客 261

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

C++进阶之构造函数与析构函数的继承:用法实例(三百一十八)

本篇目的:C++进阶之构造函数与析构函数的继承:用法实例基本概念构造函数与析构函数是C++类的重要组成部分。构造函数用于初始化对象,而析构函数用于清理和释放资源。当类发生继承时,构造函数与析构函数的行为也会受到影响。派生类在创建时不仅会调用自身的构造函数,还会涉及到基类构造函数的调用。同样,在对象销毁时,析构函数的调用顺序也是由继承关系决定的。构造函数的继承在C++中,构造函数不会被自动继承到派生类。也就是说,派生类不会继承基类的构造函数,因此需要在派生类中显式地定义自己的构造函数。

Android系统攻城狮 837

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

explicit 关键字和虚析构函数的作用

explicit关键字和虚析构函数的作用

weixin_43675296的博客 1054

构造函数、析构函数、虚函数

文章目录为什么构造函数不能为虚函数?为什么析构函数要定义为虚函数?虚函数的工作原理?有关虚函数的几个知识点 为什么构造函数不能为虚函数? 参考回答: 在类中,构造函数用于初始化对象及相关操作。 构造函数是不能声明为虚函数的,因为虚函数对应一个virtual table(虚函数表),这个表的地址是存储在对象的内存空间的。 而在执行构造函数前,对象尚未完成创建,内存都没有被分配,所以无法去查询虚函数表...

yiliacheng 996

咱们一起学C++ 第二百六十七篇之C++析构函数与虚拟析构函数的深度探索

大家好!C++学习的道路充满挑战,但每一次深入了解新的知识点,都像是解锁了新技能,让我们离编程高手又近了一步。今天咱们来探索C++中析构函数和虚拟析构函数的奥秘,希望能和大家一起进步,收获满满的知识!

wj_rdk的博客 1432

C++中为什么析构函数是虚函数

析构函数为什么是虚函数 虚构函数是虚函数的情况只需要在特定场景下出现即可,正常情况下不必要弄成虚函数。 如果基类的析构函数不是虚函数,在特定情况下会导致派生来无法被析构。 情况1:用派生类类型指针绑定派生类实例,析构的时候,不管基类析构函数是不是虚函数,都会正常析构 情况2:用基类类型指针绑定派生类实例,析构的时候,如果基类析构函数不是虚函数,则只会析构基类,不会析构派生类对象,从而造成内存泄漏。...

The Laughing Uncle的博客 2104

# C++构造函数与析构函数深度解析(8)

本文总结了C++对象生命周期管理中的核心概念——构造函数和析构函数,通过类比城市建设者与清洁工的角色,阐述了二者如何共同保障程序的内存安全。文章重点回顾了构造函数和析构函数的关键知识点,包括分类、调用时机、规则要点等,并整理成实用表格。特别强调了RAII(资源获取即初始化)这一核心思想,通过智能指针、文件管理和锁管理三个典型场景,展示了如何将资源管理与对象生命周期绑定。最后,文章建议通过实现智能数组类和线程安全计数器等实践练习来巩固所学知识,帮助开发者真正掌握这些关键概念并应用于实际编程中。

weixin_42108533的博客 798

C++构造函数与析构函数深度解析(2)

摘要 本章深入探讨C++构造函数的调用机制,重点分析三种核心场景: 栈上创建:对象随作用域自动构造/析构,遵循"后进先出"原则(如函数内局部变量) 堆上创建:通过new/delete手动控制生命周期,需警惕内存泄漏和错误释放(如动态分配对象) 临时对象:在函数传值、返回值等场景隐式创建,生命周期短暂(如函数值传递参数) 通过代码实例详解了各类场景的构造/析构时机,特别指出堆对象管理中的三大陷阱:new/delete不匹配、重复释放和内存泄漏。该内容为理解对象生命周期和内存管理奠定基础,后

weixin_42108533的博客 1045

C++中虚函数与构造/析构函数的深度解析

函数类型能否为虚函数?说明析构函数推荐且必要基类析构函数必须是虚函数,以确保通过基类指针删除派生类对象时资源正确释放。构造函数绝对不能语义矛盾,vptr未初始化,语言禁止。拷贝构造函数绝对不能同构造函数。使用虚clone()方法替代。移动构造函数绝对不能同构造函数。拷贝赋值运算符可以但不推荐可以实现"虚赋值",但容易出错,需谨慎使用。移动赋值运算符可以但不推荐同拷贝赋值运算符。

码事漫谈 980

【C++面向对象】--- 继承 的奥秘(下篇)

讲解C++继承体系:作用域、默认成员函数、继承与友元、继承和静态成员。

m0_74352571的博客 1751
上一篇: C语言 函数详解
下一篇: 一文谈Linux操作系统基础命令操作
万我.
博客等级 码龄1年 460粉丝 93原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值