当前位置: 首页 > article >正文

C++笔记 继承关系中构造和析构顺序(面向对象)

在C面向对象编程中继承是实现代码复用和类层次设计的核心特性。当存在基类与派生类的继承关系时构造函数和析构函数的调用顺序有严格的规则——这不仅是面试高频考点更是避免内存泄漏、保证对象正确初始化/清理的关键。核心结论先明确构造顺序基类 → 派生类析构顺序派生类 → 基类即“先构造父后构造子先析构子后析构父”。一、核心原理为什么是这个顺序构造函数的核心作用是初始化对象的成员变量析构函数则是清理对象占用的资源如动态内存、文件句柄等。继承关系中派生类会包含基类的所有成员公有、保护、私有私有成员仅基类可访问因此必须遵循“先初始化基类再初始化派生类”的逻辑——否则派生类使用基类成员时基类还未初始化会导致程序异常。析构函数则相反派生类的资源往往依赖于基类的资源若先析构基类派生类中依赖基类资源的部分会变成“野资源”无法正常清理进而导致内存泄漏。因此必须“先析构派生类释放其独有资源再析构基类释放基类资源”。简单记构造“从父到子”析构“从子到父”本质是“依赖关系”决定顺序——派生类依赖基类初始化先满足依赖清理先释放依赖方。二、基础案例单继承下的构造与析构顺序单继承一个派生类只继承一个基类是最常见的场景我们通过代码演示顺序结合输出结果直观理解。1. 代码实现#include iostream using namespace std; // 基类父类 class Base { public: // 基类构造函数 Base() { cout Base 构造函数调用 endl; } // 基类析构函数 ~Base() { cout Base 析构函数调用 endl; } }; // 派生类子类公有继承基类 class Derived : public Base { public: // 派生类构造函数 Derived() { cout Derived 构造函数调用 endl; } // 派生类析构函数 ~Derived() { cout Derived 析构函数调用 endl; } }; // 主函数测试 int main() { // 创建派生类对象 Derived d; // 函数结束对象自动销毁 return 0; } }2. 运行结果Base 构造函数调用 Derived 构造函数调用 Derived 析构函数调用 Base 析构函数调用3. 结果分析当创建派生类对象d时编译器会先自动调用基类Base的构造函数完成基类部分的初始化再调用派生类Derived的构造函数完成派生类独有部分的初始化。当主函数结束对象d生命周期结束编译器会先调用派生类的析构函数清理派生类的资源再调用基类的析构函数清理基类的资源完全符合“先父后子构造先子后父析构”的规则。三、进阶案例多继承下的构造与析构顺序多继承一个派生类继承多个基类时构造顺序会新增一个规则基类的构造顺序由派生类继承时的“声明顺序”决定析构顺序则与基类构造顺序相反与派生类继承声明顺序也相反。1. 代码实现#include iostream using namespace std; // 基类1 class Base1 { public: Base1() { cout Base1 构造函数调用 endl; } ~Base1() { cout Base1 析构函数调用 endl; } }; // 基类2 class Base2 { public: Base2() { cout Base2 构造函数调用 endl; } ~Base2() { cout Base2 析构函数调用 endl; } }; // 基类3 class Base3 { public: Base3() { cout Base3 构造函数调用 endl; } ~Base3() { cout Base3 析构函数调用 endl; } }; // 派生类继承顺序Base2 → Base1 → Base3 class Derived : public Base2, public Base1, public Base3 { public: Derived() { cout Derived 构造函数调用 endl; } ~Derived() { cout Derived 析构函数调用 lt;lt; endl; } }; int main() { Derived d; return 0; } }2. 运行结果Base2 构造函数调用 Base1 构造函数调用 Base3 构造函数调用 Derived 构造函数调用 Derived 析构函数调用 Base3 析构函数调用 Base1 析构函数调用 Base2 析构函数调用3. 关键结论1. 多继承的基类构造顺序严格按照派生类继承声明时的顺序示例中继承顺序是Base2、Base1、Base3因此构造顺序也是Base2→Base1→Base3与基类的定义顺序无关。2. 多继承的基类析构顺序与基类构造顺序完全相反示例中构造顺序Base2→Base1→Base3析构顺序则是Base3→Base1→Base2。3. 无论单继承还是多继承派生类的构造永远在所有基类构造之后派生类的析构永远在所有基类析构之前。四、特殊场景含成员对象的继承构造/析构顺序若派生类或基类中包含“成员对象”即类的成员是另一个类的对象则构造顺序会新增一层先构造基类 → 再构造派生类的成员对象按成员声明顺序 → 最后构造派生类本身析构顺序则相反先析构派生类 → 再析构派生类的成员对象与成员声明顺序相反 → 最后析构基类。1. 代码实现#include iostream using namespace std; // 成员对象所属的类 class Member { public: Member() { cout Member 构造函数调用 endl; } ~Member() { cout Member 析构函数调用 endl; } }; // 基类 class Base { public: Base() { cout Base 构造函数调用 endl; } ~Base() { cout Base 析构函数调用 endl; } }; // 派生类继承Base包含Member类型的成员对象 class Derived : public Base { private: // 成员对象声明顺序m1在前m2在后 Member m1; Member m2; public: Derived() { cout Derived 构造函数调用 endl; } ~Derived() { cout Derived 析构函数调用 endl; } }; int main() { Derived d; return 0; } }2. 运行结果Base 构造函数调用 Member 构造函数调用 // m1的构造 Member 构造函数调用 // m2的构造 Derived 构造函数调用 Derived 析构函数调用 Member 析构函数调用 // m2的析构 Member 析构函数调用 // m1的析构 Base 析构函数调用五、关键注意事项避坑重点1. 析构函数的“虚函数”问题多态场景当用基类指针指向派生类对象且基类析构函数不是虚函数时销毁对象时只会调用基类的析构函数派生类的析构函数不会被调用导致派生类的资源泄漏解决方案将基类的析构函数声明为虚函数virtual ~Base()此时会根据对象的实际类型派生类调用对应的析构函数保证析构顺序正确。// 正确写法基类析构为虚函数 class Base { public: virtual ~Base() { // 虚析构函数 cout Base 析构函数调用 endl; } };2. 构造函数的初始化列表基类与成员对象若基类或成员对象没有默认构造函数只有带参构造必须在派生类的初始化列表中显式调用基类和成员对象的带参构造且顺序为基类构造 → 成员对象构造与初始化列表中的顺序无关只与声明顺序有关。// 示例基类和成员对象均为带参构造 class Base { public: Base(int x) { cout Base 带参构造x x endl; } }; class Member { public: Member(int y) { cout Member 带参构造y y endl; } }; class Derived : public Base { private: Member m; public: // 初始化列表显式调用基类和成员对象的带参构造 Derived() : Base(10), m(20) { cout Derived 构造函数 endl; } };3. 不要在构造/析构函数中调用虚函数构造函数执行时对象的虚函数表尚未完全初始化此时调用虚函数只会调用当前类基类/派生类的虚函数无法实现多态析构函数执行时对象的虚函数表已开始销毁同样无法正确调用派生类的虚函数容易导致逻辑错误。六、总结必背核心无论何种继承场景构造与析构顺序的核心逻辑不变可分3类场景记忆1. 单继承无成员对象构造基类 → 派生类析构派生类 → 基类2. 多继承无成员对象构造基类按派生类继承声明顺序 → 派生类析构派生类 → 基类按构造顺序相反3. 含成员对象的继承构造基类 → 派生类成员对象按成员声明顺序 → 派生类析构派生类 → 派生类成员对象按声明顺序相反 → 基类4. 关键补充基类析构函数建议声明为虚函数多态场景必做避免资源泄漏初始化列表中基类和成员对象的构造顺序由声明顺序决定与列表顺序无关核心原则先初始化依赖的部分后初始化自身先清理自身后清理依赖的部分。掌握继承关系中的构造和析构顺序是写出安全、健壮C面向对象代码的基础也是区分基础薄弱与扎实的关键考点务必结合代码多练习、多验证。

相关文章:

C++笔记 继承关系中构造和析构顺序(面向对象)

在C面向对象编程中,继承是实现代码复用和类层次设计的核心特性。当存在基类与派生类的继承关系时,构造函数和析构函数的调用顺序有严格的规则——这不仅是面试高频考点,更是避免内存泄漏、保证对象正确初始化/清理的关键。核心结论先明确&…...

爬虫自动化(DrissionPage)

目录 ?一.介绍: 下载DrissionPage,还是我们熟悉的pip: 环境准备: ?二.基本代码: 它对于的导包和类使用: 窗口的设置: 和获取的页面的滑动: 3.进一步认识DrissionPage: 浏览器可以多开…...

Omni-Vision Sanctuary 企业级部署架构设计:高可用与弹性伸缩

Omni-Vision Sanctuary 企业级部署架构设计:高可用与弹性伸缩 1. 企业级AI部署面临的挑战 当企业决定在生产环境中部署Omni-Vision Sanctuary这类AI服务时,通常会遇到几个关键挑战。首先是服务可用性问题,任何计划外停机都可能直接影响业务…...

Phi-4-mini-reasoning助力Java安装与环境配置:从JDK到IDE的智能指引

Phi-4-mini-reasoning助力Java安装与环境配置:从JDK到IDE的智能指引 1. 为什么需要智能指引来安装Java? 刚接触Java开发的朋友们,十有八九会在环境配置这一步卡壳。我见过太多初学者在JDK版本选择、环境变量配置这些环节反复折腾&#xff0…...

3步快速上手!终极缠论量化工具:基于TradingView本地SDK的几何交易可视化完整指南

3步快速上手!终极缠论量化工具:基于TradingView本地SDK的几何交易可视化完整指南 【免费下载链接】chanvis 基于TradingView本地SDK的可视化前后端代码,适用于缠论量化研究,和其他的基于几何交易的量化研究。 缠论量化 摩尔缠论 缠…...

基于西门子PLC的空压机组储气风冷机组自动控制系统:“手动自动切换、多机控制及实时监测报警系统

基于西门子plc的空压机组储气风冷机组自动控制系统 可以实现手动自动切换 三组空压机分别自动控制,自动检测三路压力 风冷机运行实时检测 报警查寻,参数设置等上周刚把车间那套跑了快十年的空压机组控制系统给换了,用的是西门子S7-1200&#…...

感知损失(Perceptual Loss)在图像风格迁移中的关键作用与实现

1. 为什么感知损失能让AI画出更像艺术家的画? 第一次用传统MSE损失做风格迁移时,我盯着生成的"梵高星空"直挠头——颜色位置都对,但怎么看都像小学生涂鸦。直到尝试了感知损失,画面突然有了笔触的韵律感。这背后的秘密…...

算法部署设计,Sm3国密算法的硬件ip设计,纯v手写代码,图一为ip接口,图二为资源消耗

算法部署设计,Sm3国密算法的硬件ip设计,纯v手写代码,图一为ip接口,图二为资源消耗,图三四为封装为axilite接口并在开发版下板测试,图五为开发版实测结果 直接联系内容包括:sm3的软件python实现代码&#xf…...

告别‘千人千脑’:用DMMR模型搞定EEG情感识别的跨被试难题(附PyTorch代码)

突破脑电情感识别的个体差异壁垒:DMMR模型实战指南与PyTorch实现 当你在实验室里看着屏幕上跳动的脑电波形时,是否曾为不同受试者数据间的巨大差异而头疼?这种被称为"脑电指纹"的个体特异性,一直是情感识别领域最棘手的…...

西门子SMART200 PLC梯形图,SR20,昆仑通态触摸屏组态画面,常压电热水锅炉比例模糊...

西门子SMART200 PLC梯形图,SR20,昆仑通态触摸屏组态画面,常压电热水锅炉比例模糊控制追目标温度,PLC源触摸屏源CAD原理图图纸全套常压电热水锅炉那种“冰火两重天”的加热体验谁懂?茶水间或者小烘干池边上,…...

秒杀系统主库宕机不丢单方案-03-本地消息表

秒杀系统主库宕机不丢单方案:本地消息表(事务分离补偿机制) 方案概述 本地消息表方案通过在应用层引入消息表机制,将事务操作与消息发送分离,实现最终一致性。该方案是秒杀系统主库宕机不丢单的兜底设计,即…...

Akagi技术深度解析:开源雀魂AI辅助工具完全实战指南

Akagi技术深度解析:开源雀魂AI辅助工具完全实战指南 【免费下载链接】Akagi 支持雀魂、天鳳、麻雀一番街、天月麻將,能夠使用自定義的AI模型實時分析對局並給出建議,內建Mortal AI作為示例。 Supports Majsoul, Tenhou, Riichi City, Amatsuk…...

秒杀系统主库宕机不丢单方案-02-半同步AFTER_SYNC

秒杀系统主库宕机不丢单方案:半同步AFTER_SYNC(主从确认再提交) 方案概述 半同步复制AFTER_SYNC方案是MySQL 5.7版本引入的高级复制机制,通过主从节点之间的确认机制确保数据不丢失。该方案在主库提交事务前,等待至少一…...

一站式AI应用开发:在PyTorch 2.8环境中集成Dify与Ollama部署大模型

一站式AI应用开发:在PyTorch 2.8环境中集成Dify与Ollama部署大模型 1. 企业级AI开发的新范式 想象一下这样的场景:你的开发团队需要在两周内上线一个智能客服系统,要求能理解专业术语、生成高质量回复,还要能与企业现有系统无缝…...

技术洞察:zyfun如何重构跨平台视频播放体验

技术洞察:zyfun如何重构跨平台视频播放体验 【免费下载链接】zyfun 跨平台桌面端视频资源播放器,免费高颜值. 项目地址: https://gitcode.com/gh_mirrors/zy/zyfun 在数字娱乐快速发展的今天,跨平台视频播放器面临着系统兼容性、性能优化和用户体…...

HsMod:炉石传说个性化增强工具 玩家的全方位游戏体验优化方案

HsMod:炉石传说个性化增强工具 玩家的全方位游戏体验优化方案 【免费下载链接】HsMod Hearthstone Modify Based on BepInEx 项目地址: https://gitcode.com/GitHub_Trending/hs/HsMod 你是否曾因炉石传说中繁琐的操作流程而感到沮丧?是否希望拥有…...

GNU Radio滤波器设计实战指南:从原理到高性能实现

GNU Radio滤波器设计实战指南:从原理到高性能实现 【免费下载链接】gnuradio GNU Radio – the Free and Open Software Radio Ecosystem 项目地址: https://gitcode.com/gh_mirrors/gn/gnuradio GNU Radio作为开源软件定义无线电生态系统,提供了…...

【数据结构】红黑树(Red-Black Tree)

前言在上一篇博客中,我们学习了 AVL 树,为了保持绝对的平衡,它在插入和删除时会疯狂地进行左旋和右旋。但在现代的Java集合框架中(如 TreeMap、TreeSet,以及 Java 8 之后的 HashMap),并没有选择…...

微信好友检测神器:一键识别谁删了你,轻松管理社交圈

微信好友检测神器:一键识别谁删了你,轻松管理社交圈 【免费下载链接】WechatRealFriends 微信好友关系一键检测,基于微信ipad协议,看看有没有朋友偷偷删掉或者拉黑你 项目地址: https://gitcode.com/gh_mirrors/we/WechatRealFr…...

3步打造高效右键菜单:让Windows操作提速50%

3步打造高效右键菜单:让Windows操作提速50% 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否也曾在右键点击文件时,面对长达20个选项…...

Qwen-Edit-2509多角度切换技术:如何用单张图片生成全视角内容?

Qwen-Edit-2509多角度切换技术:如何用单张图片生成全视角内容? 【免费下载链接】Qwen-Edit-2509-Multiple-angles 项目地址: https://ai.gitcode.com/hf_mirrors/dx8152/Qwen-Edit-2509-Multiple-angles 在视觉创作领域,你是否曾为拍…...

抑制素A抗体如何提升妊娠中期唐氏综合征筛查的效能?

一、为何抑制素A成为妊娠期的重要生物标志物?抑制素A是一种由α和βA亚基通过二硫键连接形成的异源二聚体糖蛋白。在非妊娠期,它主要由卵巢颗粒细胞分泌,作为反馈调节因子,选择性地抑制垂体前叶分泌卵泡刺激素。进入妊娠状态后&am…...

Vue2项目构建优化实战:时间戳防缓存与资源压缩的配置详解

1. 为什么Vue2项目需要构建优化 最近接手了一个老项目的维护工作,发现每次前端更新后总有用户反馈页面显示异常。排查后发现是浏览器缓存惹的祸——用户访问的仍然是旧版本的静态资源。这让我意识到构建优化的重要性,特别是对于需要频繁更新的业务系统。…...

数字记忆自主化:GetQzonehistory技术架构与数据保护实践指南

数字记忆自主化:GetQzonehistory技术架构与数据保护实践指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 一、技术演进视角下的数据脆弱性危机 数字存储技术的迭代速度与…...

Windows驱动存储深度管理:从问题诊断到系统优化的完整解决方案

Windows驱动存储深度管理:从问题诊断到系统优化的完整解决方案 【免费下载链接】DriverStoreExplorer Driver Store Explorer [RAPR] 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 问题发现:驱动管理中的隐形痛点与风险 系…...

Kandinsky-5.0-I2V-Lite-5s实战:基于Dify平台构建无代码视频生成应用

Kandinsky-5.0-I2V-Lite-5s实战:基于Dify平台构建无代码视频生成应用 1. 引言:让图片动起来的零门槛方案 最近遇到不少朋友在问:有没有什么简单的方法,能让静态图片变成动态视频?传统方案要么需要专业视频编辑技能&a…...

魔兽争霸3终极优化指南:如何解锁180fps帧率限制并解决现代硬件兼容性问题

魔兽争霸3终极优化指南:如何解锁180fps帧率限制并解决现代硬件兼容性问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 魔兽争霸3作为经…...

从零到专业:League Director 让你的英雄联盟回放变成电影级大片

从零到专业:League Director 让你的英雄联盟回放变成电影级大片 【免费下载链接】leaguedirector League Director is a tool for staging and recording videos from League of Legends replays 项目地址: https://gitcode.com/gh_mirrors/le/leaguedirector …...

YouTube视频一直转圈?加载卡顿原因分析与排查方法(2026)

在日常开发或使用在线视频平台时,常见一个问题:视频播放过程中出现持续加载、卡顿甚至无法播放的情况。这类问题并不一定由带宽不足引起,而往往与浏览器、网络链路以及设备性能等多方面因素有关。本文从技术角度出发,对视频加载流…...

ESP32 RMT硬件驱动RF遥控库:替代rc-switch的异步OOK方案

1. 项目概述RCSwitchRmt 是一款专为 ESP32 系列微控制器设计的射频(RF)OOK(On-Off Keying,开关键控)通信库,其核心目标是提供一种现代、异步、非阻塞的硬件驱动型替代方案,以取代广为人知但已显…...