Cracking the coding interview--Q13.7

February 14, 2013
作者:Hawstein
出处:http://hawstein.com/posts/13.7.html
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。

题目

原文:

Why does a destructor in base class need to be declared virtual?

译文:

为什么基类中的析构函数要声明为虚析构函数?

解答

用对象指针来调用一个函数,有以下两种情况:

  1. 如果是虚函数,会调用派生类中的版本。

  2. 如果是非虚函数,会调用指针所指类型的实现版本。

析构函数也会遵循以上两种情况,因为析构函数也是函数嘛,不要把它看得太特殊。 当对象出了作用域或是我们删除对象指针,析构函数就会被调用。

当派生类对象出了作用域,派生类的析构函数会先调用,然后再调用它父类的析构函数, 这样能保证分配给对象的内存得到正确释放。

但是,如果我们删除一个指向派生类对象的基类指针,而基类析构函数又是非虚的话, 那么就会先调用基类的析构函数(上面第2种情况),派生类的析构函数得不到调用。

请看例子:

class Base{
public:
    Base() { cout<<"Base Constructor"<<endl; }
    ~Base() { cout<<"Base Destructor"<<endl; }
};
class Derived: public Base{
public:
    Derived() { cout<<"Derived Constructor"<<endl; }
    ~Derived() { cout<<"Derived Destructor"<<endl; }
};
int main(){
    Base *p = new Derived();
    delete p;
    return 0;
}

输出是:

Base Constructor
Derived Constructor
Base Destructor

如果我们把基类的析构函数声明为虚析构函数,这会使得所有派生类的析构函数也为虚。 从而使析构函数得到正确调用。

将基类的析构函数声明为虚的之后,得到的输出是:

Base Constructor
Derived Constructor
Derived Destructor
Base Destructor

因此,如果我们可能会删除一个指向派生类的基类指针时,应该把析构函数声明为虚函数。 事实上,《Effective C++》中的观点是,只要一个类有可能会被其它类所继承, 就应该声明虚析构函数。

全书题解目录:

Cracking the coding interview–问题与解答

全书的C++代码托管在Github上:

https://github.com/Hawstein/cracking-the-coding-interview