虚析构函数必须声明为virtual,否则通过基类指针delete子类对象时子类析构函数不会被调用,导致资源泄漏;只要存在多态删除场景(如工厂返回指针、容器存储基类指针等),就必须加;基类声明virtual析构后,派生类析构自动为虚,建议显式加override。
delete 父类指针时子类析构函数根本不会调用这是最直接的后果。当用 Base* 指向一个 Derived 对象,且 Base::~Base() 不是 virtual 时,delete ptr 只会调用 Base::~Base(),Derived::~Derived() 完全被跳过。如果子类在析构里释放文件句柄、内存、网络连接或调用 close()/delete,这些操作就彻底漏掉了。
常见错误现象:
Too many open files)delete
virtual?看多态删除是否可能发生不是“只要用了继承就要加”,而是“只要存在通过基类指针/引用创建子类对象,并可能用基类指针 delete 它”的场景,就必须加。典型包括:
std::unique_ptr 或裸指针std::vector<:unique_ptr>>
反例:子类只用于栈上对象(Derived d;),或完全不通过基类指针销毁,则虚析构不是必需的——但加了也没坏处,且容易误判使用方式,所以只要类设计为被继承,就应默认加 virtual。
virtual 析构函数对性能和 ABI 的影响其实极小有人担心虚函数表开销或调用成本,但现实是:
sizeof)virtual void foo() = 0;),加 virtual 析构几乎零成本真正代价是没加带来的不确定性——你永远不知道下游用户会不会拿你的类做多态删除。
virtual,子类无需显式加 virtual
只要基类析构是 virtual,派生类的析构自动成为虚函数,即使不写 virtual 关键字。但建议显式写出,提高可读性:
class Base {
public:
virtual ~Base() = default; // ✅ 推荐:= default 更清晰
};
class Derived : public Base {
public:
virtual ~Derived()

override { / 清理子类资源 / } // ✅ 显式 + override
};注意:= default 和 {} 都可以,但避免写成 ~Base() {} —— 这会抑制编译器生成移动操作,且语义不如 = default 明确。
最容易被忽略的一点:纯虚析构函数必须提供定义,哪怕为空:
class Interface {
public:
virtual ~Interface() = 0; // 声明纯虚
};
Interface::~Interface() = default; // ✅ 必须定义,否则链接失败虚析构函数不是“最佳实践”的点缀,而是多态对象生命周期管理的契约底线——漏掉它,等于把资源释放的控制权交给了未定义行为。