为多态基类声明virtual析构函数
先来看一个例子,代码如下:
#include <iostream> using namespace std; class Animal { public: Animal() { std::cout << "base class's constructor" << std::endl; } /*virtual*/ ~Animal() { std::cout << "base class's destory constructor" << std::endl; } virtual void eat() = 0; }; class Lion : public Animal { public: Lion() { std::cout << "Lion class's destory constructor" << std::endl; } ~Lion() { std::cout << "Lion class's destory constructor" << std::endl; } void eat() override { std::cout << "Lion eat action" << std::endl; } }; int main() { Animal *pAnimal = new Lion(); pAnimal->eat(); delete pAnimal; return 0; }
输出如下:
base class's constructor
Lion class's destory constructor
Lion eat action
base class's destory constructor
根据打印的日志发现,子类的析构函数居然没被调用!!!
当基类的指针指向派生类的对象的时候,当我们使用完,对其调用delete的时候,其结果将是未有定义——基类成分通常会被销毁,而派生类的析构函数没被执行,于是造成一个诡异的"局部销毁"对象。这可是形成资源泄漏、败坏之数据结构、产生BUG的根源。
消除以上问题的做法很简单:给基类一个virtual析构函数,此后删除派生类对象就会如你想要的那般。
但是,无端地将所有class的析构函数声明为virtual,就像从未声明它们为virtual一样,都是错误的。因为每一个带有virtual函数的class都有一个相应的vbtl(指向虚函数表的指针vtbl),此对象因为vtbl的引入而不再和其他语言(如C)内的相同声明有着一样的结构,因此也就不在可能把它传递至(或接受自)其他语言所写的函数,因此不再具有移植性。
任何类只要带有virtual函数都几乎确定应该也有一个virtual析构函数。
如果一个类不含virtual函数,通常表示它并不意图被用做一个基类,当类不企图被当做基类时,令其析构函数为virtual往往是个馊主意。
总结:
- 带有多态性质的基类应该声明一个virtual析构函数。如果类带有任何virtual函数,它就应该拥有一个virtual析构函数。
- 一个类的设计目的不是作为基类使用,或不是为了具备多态性,就不该声明virtual析构函数。
- STL容器都不带virtual析构函数,所以最好别派生它们。

浙公网安备 33010602011771号