0

0

C++中的析构函数为什么要写成虚函数?(不写会有什么后果)

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-02-26 14:39:11

|

199人浏览过

|

来源于php中文网

原创

必须为基类析构函数声明virtual,否则通过base*删除derived对象时会跳过子类析构,导致资源泄漏;仅当基类不被多态删除、禁止继承、或用于编译期多态等场景才可省略。

c++中的析构函数为什么要写成虚函数?(不写会有什么后果)

不写虚析构函数时,delete 父类指针会漏掉子类析构逻辑

当用 Base* 指向一个 Derived 对象,并通过该指针调用 delete 时,若 Base::~Base() 不是虚函数,C++ 只会调用 Base 的析构函数,完全跳过 Derived::~Derived()。这意味着子类中申请的资源(如堆内存、文件句柄、socket 连接等)不会被释放。

常见错误现象:valgrind 报告内存泄漏;程序运行一段时间后崩溃或卡死;调试时发现对象内部指针没被置空、资源未关闭。

  • 只在基类需要被多态删除时才必须加 virtual —— 如果类不作为接口、不被继承、或从不通过基类指针 delete,就不需要
  • 即使析构函数函数体为空,也得显式声明为 virtual ~Base() = default;virtual ~Base() {}
  • 纯虚析构函数也要提供定义(哪怕空实现),否则链接失败:virtual ~Base() = 0; 后必须在 .cpp 中写 Base::~Base() {}

虚析构函数不会影响性能,但能避免未定义行为

虚函数表指针(vptr)开销只在对象创建时发生一次,析构本身不比非虚版本慢。真正代价是:没加 virtual 导致的未定义行为(UB)—— C++ 标准不保证任何结果,可能表现为“看似正常”,也可能在优化级别升高后突然出错。

典型陷阱:

Warp
Warp

新一代的终端工具(内置AI命令搜索)

下载

立即学习C++免费学习笔记(深入)”;

  • 使用 std::unique_ptr<base> 管理派生类对象,若 Base 析构非虚,unique_ptr 的默认删除器仍只会调用 Base::~Base()
  • 工厂函数返回 std::shared_ptr<base>,同样依赖基类析构是否为虚来决定资源清理完整性
  • RAII 类型(如自定义锁、临时文件管理器)若被继承且析构非虚,其自动清理机制就失效了

哪些情况可以不写虚析构函数?

不是所有基类都需要虚析构。关键判断依据是:有没有可能通过基类指针(或智能指针)去销毁派生类对象。

  • 类设计为 final(class Base final),明确禁止继承 → 不需要
  • 类仅作类型抽象(如 tag dispatch 用的空结构体),不含资源管理逻辑 → 可省略
  • 继承关系仅用于编译期多态(模板特化、CRTP),运行时无 Base* 指向 Derived 对象 → 不需要
  • 派生类对象总是栈上创建、或由专用删除器管理(如自定义 deleter 传给 unique_ptr)→ 基类析构可不虚,但需确保删除路径可控

现代 C++ 中更安全的替代方案

虚析构解决的是“通过基类接口销毁派生对象”的问题,但如果你能避开这个模式,就能绕过风险。比如:

  • 用模板替代继承:把算法逻辑写成函数模板,接受任意满足接口的类型,而非继承同一基类
  • std::variantstd::any 替代运行时多态,配合 std::visit 显式分发
  • 若必须多态,优先用 std::shared_ptr 并配合自定义删除器(在构造时绑定具体类型析构逻辑),但这增加了复杂度,不如直接加 virtual 简洁

虚析构看起来只是加个关键字,但它锁定了整个继承体系的资源生命周期语义。漏掉它,往往要等到压测或上线后才暴露,而且很难复现。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

385

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

200

2025.07.04

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1657

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

506

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2310

2025.12.29

batoto漫画官网入口与网页版访问指南
batoto漫画官网入口与网页版访问指南

本专题系统整理batoto漫画官方网站最新可用入口,涵盖最新官网地址、网页版登录页面及防走失访问方式说明,帮助用户快速找到batoto漫画官方平台,稳定在线阅读各类漫画内容。

331

2026.02.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10.2万人学习

C 教程
C 教程

共75课时 | 5万人学习

C++教程
C++教程

共115课时 | 19.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号