虚析构函数确保通过基类指针删除派生类对象时能正确调用派生类析构函数,避免资源泄漏;只要类可能被继承且存在多态删除场景,就必须声明为virtual,推荐写法为virtual ~Base() = default;。

虚析构函数的核心作用不是直接“防止内存泄漏”,而是确保通过基类指针删除派生类对象时,能正确调用派生类的析构函数。如果没声明为虚函数,只会调用基类析构函数,导致派生类中申请的资源(如动态内存、文件句柄等)无法释放——这才是引发内存泄漏等资源泄漏的根本原因。
为什么基类析构函数需要是虚函数?
当用 基类指针指向派生类对象,并用 delete 删除时,C++ 默认按指针静态类型(即基类)决定调用哪个析构函数。若基类析构函数非虚,编译器不会进行动态绑定,派生类析构函数根本不会执行。
- 基类析构函数非虚 → 只调用基类析构函数 → 派生类成员(如
int* p = new int[100];)未被清理 → 内存泄漏 - 基类析构函数为虚 → 运行时根据实际对象类型调用完整析构链(派生类→基类)→ 资源逐级释放
什么情况下必须写虚析构函数?
只要类设计为“可能作为基类被继承”,且**存在多态删除场景**(即通过基类指针/引用管理派生类对象生命周期),就必须将析构函数声明为 virtual。
- 常见于接口类(纯虚函数类)、抽象基类(如
Shape,Logger) - 即使基类没有数据成员或资源,只要用户可能用
Base* p = new Derived;+delete p;,就该加virtual - 如果类明确不用于继承(比如加了
final),或从不通过基类指针删除对象,则无需虚析构
怎么正确声明和定义?
通常在基类中声明为 virtual,可以是纯虚(= 0)或带空实现;派生类析构函数会自动成为虚函数,无需显式加 virtual 关键字。
立即学习“C++免费学习笔记(深入)”;
- 推荐写法:
virtual ~Base() = default;(C++11起,简洁安全) - 也可写:
virtual ~Base() { }(显式空实现) - 避免只声明不定义:虚析构函数必须有定义,否则链接失败
一个典型错误示例
下面代码看似正常,但会漏掉派生类资源清理:
class Base {
public:
~Base() { cout << "Base dtor\n"; } // ❌ 非虚 → 危险!
};
class Derived : public Base {
int* data;
public:
Derived() : data(new int[1000]) {}
~Derived() { delete[] data; cout << "Derived dtor\n"; }
};
// ...
Base* p = new Derived;
delete p; // 输出只有 "Base dtor" → data 泄漏!
改成 virtual ~Base() = default; 后,输出变为 "Derived dtor" → "Base dtor",资源正确释放。










