转自:http://blog.sina.com.cn/s/blog_74233e710100zbkf.html
在《C++ primer》,以及在Meyers的《Effective C++》《More Effective C++》中都提到过virtual析构函数,在这里做一下总结。
class Base{
public:
};
class Derive:public Base{...};
Base *pb=new Derive(...);
...
delete pb;
C++中明确指出,当派生类对象经由一个基类指针被删除,而此基类仅提供了non-virtual析构函数,其结果是未定义的。如果删除基类指针,则需要运行基类构造函数并清除基类的成员,如果对象实际是指向派生类类型的对象,则没有定义这种行为。实际执行是通常发生的是对象的derived成分没有被销毁,而派生类中的base class成分通常会被销毁,这就造成了一个“局部销毁”的对象,从而造成资源泄露。消除这个问题很简答:给base class一个virtual析构函数,这会保证运行适当的析构函数。
class Base{
public:
};
class Derive:public Base{...};
Base *pb=new Derive(...);
...
delete pb;
Now,现在就有这样一个问题,是不是要把所有的class的析构函数都要带上virtual呢,这同样是错误的。要实现virtual函数,对象必须携带某些信息,主要用来在运行时决定哪一个virtual函数应该被调用。这份信息通常是由一个所谓vptr(virtual table pointer)指针指出。vptr指向一个由函数指针构成的数组,成为vtbl(virtual table);每一个带有virtual函数的class都有一个相应的vtbl。当对象调用一个virtual函数,实际被调用的函数取决于该对象的vptr所指的那个vtbl,编译器在其中寻找适当的函数指针。当然在Scott Meyers的另一本书《More Effective C++》中有详细的介绍,同时尝试实现虚函数机制。virtual函数的实现细节并不重要,重要的是如果class中含有virtual函数,其对象的体积会增加,这会带来许多麻烦问题。
即使class完全不带virtual函数,就要注意了,不要试图去继承它。如标准的string和标准库中的容器vector,list,set等都不带有任何的virtual函数,如果你试图写这样的代码:
class SpecialString:pulic std::string{...};
文章刚开始提到过的问题,你是不是能够避免呢?有时候你会不自觉的义正言辞的去做的。拒绝诱惑吧,毕竟C++没有提供类似于Java的final class禁止派生机制。
有时候令class带有一个pure virtual析构函数,可能会带来便利,如Meyers在《More Effective C++》中“条款33:将非尾端类设计为抽象类”曾经提到过的那样。
class Base{
public:
};
这样Base成为一个abstract class,当有时候你希望拥有abstract class,但是没有任何pure virtual函数怎么办?很简答:为你希望成为abstract class的那个class声明一个pure virtual析构函数吧。虽然abstract class不能被实例化,但是别忘了需要为pure virtual析构函数提供一个定义,这也只能在类外进行了:
Base::~Base(){}
毕竟,派生类析构函数还是回调用此函数来析构其相应部分的。
最后请记住:
1)
2)