news 2026/4/23 12:16:47

《你真的了解C++吗》No.029:抽象类的构造与析构——不存在的实体,存在的基石

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《你真的了解C++吗》No.029:抽象类的构造与析构——不存在的实体,存在的基石

《你真的了解C++吗》No.029:抽象类的构造与析构——不存在的实体,存在的基石

导言:一个逻辑悖论?

在 No.022 中我们聊过,抽象类(包含纯虚函数的类)是无法实例化的。如果你写AbstractShape s;,编译器会直接把你挡在门外。

既然这种类永远不会在内存中独立存在,很多人就会产生疑问:它还需要构造函数和析构函数吗?答案是:不仅需要,而且它们在对象“拼图”的完成中起着不可替代的作用。


一、 物理本质:派生类是个“夹心饼干”

要理解为什么抽象类需要构造函数,必须看清派生类对象的内存物理排布。

当你创建一个Circle对象(继承自抽象类Shape)时,在内存中:

  1. 底层:是Shape的成员变量和虚指针。
  2. 上层:是Circle特有的成员变量。

构造规则
C++ 规定,任何对象的初始化必须遵循**“先祖后辈”**的顺序。当Circle构造时,它必须首先调用Shape的构造函数来初始化基类那部分的成员。即使Shape是抽象的,它依然拥有需要被初始化的数据(比如colorvptr)。


二、 抽象类构造函数的“幕后黑手”

抽象类的构造函数通常被声明为protected。这样做有两个原因:

  1. 限制访问:既然外界不能实例化它,暴露public构造函数没有意义。
  2. 强制协作:它明确告诉开发者,这个构造函数是专门给子类在初始化列表(Member Initialization List)里调用的。
classShape{// 抽象类protected:intid;Shape(inti):id(i){}// 依然可以有逻辑public:virtualvoiddraw()=0;};classCircle:publicShape{public:Circle(inti):Shape(i){}// 子类必须显式调用基类构造};

三、 析构函数:抽象类最容易犯错的地方

这是本章最核心的警示:抽象类的析构函数绝不能省略,且必须是虚的(virtual)。

即使一个类是抽象的,当通过基类指针删除子类对象时,如果析构函数不是虚的,就会发生内存泄漏:

Shape*p=newCircle();deletep;// 如果 ~Shape() 不是虚的,Circle 的析构函数永远不会被调用

纯虚析构函数的特殊性
你甚至可以把析构函数声明为纯虚的,来强迫这个类变成抽象类:
virtual ~Shape() = 0;
但请记住,你必须为这个纯虚析构函数提供函数体Shape::~Shape() {}),因为子类析构时,最终一定会向上调用基类的析构函数。如果没有定义,链接器会报错。


四、 编译器生成的“隐形代码”

即使你没在抽象类里写构造函数,编译器也会为你生成一个默认的。
这个隐形函数最重要的任务不是初始化变量,而是初始化虚指针(vptr)

  • Shape的构造过程中,vptr会被暂时指向Shape的虚表。
  • 随后在Circle的构造过程中,vptr才会被重写为指向Circle的虚表。
    这个“vptr 演变”的过程,决定了我们在下一章(No.030)要讨论的那个致命陷阱。

总结:抽象类不“空”

  • 构造函数:是为了确保派生类中属于基类的那部分内存被正确初始化。
  • 析构函数:是为了确保通过多态删除对象时,清理链条不会断裂。
  • 抽象类是一个半成品,构造函数则是组装这个半成品不可或缺的工序。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 16:59:30

建议收藏!大模型开发必知:10个核心概念详解,从RAG到推理加速,助你成为AI产品专家

本文详解大模型开发的10个核心概念,包括RAG、Agent、函数调用、思维链、向量数据库、量化、蒸馏、LoRA、剪枝和推理加速。每个概念从定义、实现方法和注意事项进行解析,帮助开发者理解AI应用落地的技术栈,做出正确的技术选择。文章还提供原型…

作者头像 李华
网站建设 2026/4/18 7:28:21

DevSecOps工具市场迎来爆发期:国产化与智能化双轮驱动下的产业变革

DevSecOps工具市场迎来爆发期:国产化与智能化双轮驱动下的产业变革 随着数字化转型进入深水区,软件开发领域正在经历一场深刻的安全范式转移。Gartner最新预测显示,到2026年中国DevSecOps工具市场规模将突破78亿元,年复合增长率高…

作者头像 李华
网站建设 2026/4/23 10:46:50

【通信原理】数字通信系统特点详解:构建现代信息时代的基石

当今社会,我们已经完全步入信息时代。从手机通话到视频会议,从物联网设备到卫星通信,这些看似日常的通信方式背后,都依赖于数字通信技术的支撑。数字通信不仅仅是一种技术,更是一种推动人类信息交互方式革新的力量。本…

作者头像 李华
网站建设 2026/4/17 22:43:20

3.9 Operator模式深度解析:用Kubebuilder构建自定义CRD和控制器

Operator模式深度解析:用Kubebuilder构建自定义CRD和控制器 引言 Operator 模式是 Kubernetes 扩展的核心机制,通过自定义资源(CRD)和控制器实现复杂应用的管理。Kubebuilder 是构建 Operator 的官方框架。本文将深入讲解 Operator 模式和 Kubebuilder 的使用,通过实战案…

作者头像 李华
网站建设 2026/4/5 21:31:59

找商网 item_get - 获得商品详情接口对接全攻略:从入门到精通

找商网 item_get 接口(官方标准命名 zhaoshang.item.get)是面向工业品、机械设备、原材料、五金工具等 B2B 批发场景的核心商品详情接口,通过商品唯一标识 item_id 可获取商品的基础属性、技术参数、价格体系、库存状态、商家信息、交易保障等…

作者头像 李华
网站建设 2026/4/18 3:05:13

【Linux指南】Linux命令行进度条实现原理解析

【Linux指南】Linux 命令行进度条实现原理解析 Linux 命令行(终端)中的进度条(如 wget、dd、pv、curl --progress-bar、各种部署脚本等看到的动态条)本质上不是图形控件,而是纯文本 终端控制技巧的组合。 核心原理一…

作者头像 李华