可能是重复问题:
何时使用虚析构函数?
在什么情况下,你的C++对象的析构函数应该是virtual
?
可能是重复问题:
何时使用虚析构函数?
在什么情况下,你的C++对象的析构函数应该是virtual
?
因为使用虚函数的原因是使用多态。这意味着你将在基类指针上调用一个方法,并且你想要最终实现 - 这就是多态的整个意义。
现在,如果你没有虚析构函数,而是通过基类指针调用析构函数,那么你最终会调用基类的析构函数。在这种情况下,你希望多态性也能在析构函数上工作,例如通过在基类上调用析构函数,你希望调用最终派生类的析构函数,而不是基类的析构函数。
class A
{
virtual void f() {}
~A() {}
}
class B : public A
{
void f() {}
~B() {}
}
A * thing = new B();
thing->f(); // calls B's f()
delete thing; // calls ~A(), not what you wanted, you wanted ~B()
将 ~A() 声明为虚函数可以启用多态性
virtual ~A() {}
所以当你现在调用时
delete thing;
~B()将会被调用。
当你设计一个类作为接口时,你应该声明虚析构函数,例如你希望它被扩展或实现。在这种情况下,一个好的做法是拥有一个接口类(类似于Java中的接口)具有虚方法和虚析构函数,然后有具体实现类。
可以看到STL类没有虚析构函数,因此不应该被扩展(例如std::vector、std::string...)。如果你扩展了std::vector并且通过指针或引用调用基类的析构函数,你肯定不会调用你专门的类析构函数,这可能会导致内存泄漏。
那么什么时候应该声明虚析构函数?每当类至少具有一个虚函数时。拥有虚函数意味着该类旨在作为接口对派生类进行操作,当这样做时,派生类的对象可以通过指向基类的指针被销毁。
关于何时应将析构函数声明为虚拟的,有很多额外信息在C++ FAQ上。(感谢Stobor)
什么是虚拟成员?来自C++ FAQ:
[20.1]什么是“虚成员函数”?
从面向对象的角度来看,它是C++中最重要的特性:[6.9],[6.10]。
虚函数允许派生类替换基类提供的实现。编译器确保在对象实际上是派生类时始终调用替换,即使通过基指针而不是派生指针访问对象。这允许在派生类中替换基类中的算法,即使用户不知道派生类也能如此。
派生类可以完全替换(“覆盖”)基类成员函数,或者派生类可以部分替换(“扩充”)基类成员函数。后一种情况是通过让派生类成员函数调用基类成员函数来实现的,如果需要的话。
始终如此。
除非我真的关心vtable的存储和性能开销,我总是将其设为虚拟的。除非你有一个静态分析工具可以验证你的析构函数在正确的情况下是虚拟的,否则在需要时没有做出虚拟析构函数而犯错是不值得的。