C++指出,当派生对象经由基类指针被删除,而该基类带有一个非虚析构函数,其结果未有定义。
实际执行时,通常发生的是派生对象成分没被销毁。基类通常会被销毁,造成一个“局部销毁”对象。解决方法很简单,给基类一个虚析构函数,此后删除的派生类对象就会如你想要的那般。
任何函数只要带有虚函数,都几乎确定应该带有一个虚析构函数
如果类内不含虚函数,通常表示它并不意图被用做一个基类,当类不被企图当作基类,令其析构函数为虚函数通常是个馊主意。
欲实现出虚函数,对象必须携带某些信息,主要用来在运行期决定哪一个虚函数该被调用。这份信息通常是由一个所围的vptr(virtual table pointer)指针指出。虚表指针指向一个由函数指针构成的数组,称为vtbl(virtual table)。每一个带有虚函数的class都有一个相应的虚函数表。
当对象调用某一个虚函数,实际被调用的取决于vptr所指的那个vtbl——编译器在其中寻找适当的函数指针。
只有当class内含至少一个虚函数才为它声明虚析构函数。
纯虚函数导致抽象类——也就是不能被实体化的类。
class A{
public:
virtual ~A()=0; //声明纯虚函数
}
但必须为这个纯虚函数提供一份定义:
A::~A(){} //纯虚函数的定义
析构函数的运作方式是,最深层派生的那个类的析构函数最先被调用,然后是其每一个基类的析构函数被调用。
编译器会在A的派生类的析构函数中创建一个对~A的调用动作,所以你必须为这个函数提供一份定义。
“给基类一个虚析构函数”,这个规则只适用于带多态性质的基类身上。这个基类的设计目的是为了用来“通过基类接口处理派生类对象”。并非所有的 基类设计都是为了多态用途,例如标准string和STL容器。
请记住:
- 带多态性质的基类应该声明一个虚析构函数。如果类带有任何虚函数,它就应该拥有一个虚析构函数
- 类设计的目的如果不是作为基类使用,或不是为了具备多态性,就不应该声明虚析构函数