当基类与子类均使用默认析构函数时,基类仍需虚析构函数吗?
基类有虚函数但用默认析构时,要不要加虚析构?
嘿,这个问题问到点子上了!很多人以为只有子类有自定义析构的时候才需要虚析构,其实不是这么回事——咱们得从多态销毁的核心规则说起:
核心场景:通过基类指针删除子类对象
只要你会用到「基类指针/引用指向子类对象,然后通过这个指针删除对象」的场景,不管子类有没有自定义析构函数,基类都必须有虚析构函数。否则这会触发C++标准里的未定义行为——哪怕子类的默认析构看起来只是“啥也没做”,也不能掉以轻心。
举个你给出的代码例子,稍微补全一下问题场景:
#include <string> using namespace std; class Printable { public: virtual string print() = 0; // 这里没有虚析构函数 ~Printable() = default; // 普通的默认析构 }; class A : public Printable { int foo; bool bar; string str; public: string print() override { return "A"; } // 子类用默认析构 }; int main() { Printable* ptr = new A(); delete ptr; // 这里是未定义行为! return 0; }
这段代码里,A的析构是默认的,但因为Printable的析构不是虚的,编译器不会沿着继承链调用A的析构——虽然A的成员都是基础类型或STL容器(STL容器自己会管理资源),看起来可能不会出问题,但未定义行为意味着程序可能崩溃、内存泄漏,或者表现出任何奇怪的行为,这绝对是要避免的。
为什么有虚函数的基类建议加虚析构?
既然你的Printable类已经有了虚函数print(),说明它就是为多态设计的——大概率会出现基类指针指向子类对象的场景。这时候给基类加虚析构是零成本的最佳实践:
- 只要基类的析构被声明为虚的,子类的默认析构会自动成为虚析构(继承特性);
- 编译器会自动生成正确的虚析构逻辑,保证销毁对象时从子类到基类的析构函数都被调用;
- 完全不会带来额外的性能负担(除非你在极端性能敏感的场景,但这种场景一般也不会用多态)。
什么时候可以不用?
如果你的基类虽然被继承,但永远不会通过基类指针/引用删除子类对象,理论上可以不用虚析构。但说实话,这种场景非常少见——既然已经给基类加了虚函数,就说明你是要用到多态的,与其赌“永远不会这么用”,不如直接加上虚析构,彻底避免踩坑。
总结一下:只要你的基类是多态基类(有虚函数),不管子类有没有自定义析构,都应该给基类声明虚析构函数。
内容的提问来源于stack exchange,提问作者Jackson
相关产品推荐
相关产品推荐

