一、多态基类为什么要声明虚析构函数
当derived class对象经由一个base class指针被删除,而该bass class 带着一个non-virtual吸狗善书,其结果未有定义——实际执行时通常发生的是对象的的derived成分没有被销毁。
二、为什么多态基类中声明为虚析构函数,派生类就会被析构?
- 析构函数的运作方式:最深层派生的那个class其析构函数最先被调用,然后是其每一个base class的析构函数被调用。
- 抽象类的析构函数声明为纯虚析构函数:若想拥有一个抽象类,但又没有其他pure virtual 函数,可以将析构函数声明为pure virual。因为抽象类一般是被用来做基类的,而基类应该有个虚析构函数(抽象类中有其他virtual函数)。但是注意,应该为抽象类的纯虚析构函数做个实现,否则编译器会报错(编译器会在derived class的析构中创建一个对base class析构函数的调用)。
- 基类的指针指向派生类时,若基类的析构函数为虚函数,派生类的虚表中会重写基类的析构函数,当通过基类的指针释放派生类性别的对象时,调用的是派生类的析构函数,而派生类的析构函数中会调用基类的析构函数。虽然派生类的析构函数和基类的析构函数不同名,但是也会发生重写。
三、当class不企图被当作base class,令其析构函数为virtual导致的问题
- vptr(虚表指针):指向一个由函数指针构成的数组。
- vtbl(虚表):每一个带有virtual函数的class都有一个相应的vtbl。
当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指的那个vtbl——编译器在其中寻找适当的函数指针。
32位系统中,指针占4个字节,64位系统中,指针占8个字节。当class中包含virtual函数时,对象的大小会增加4~8个字节。这会导致c++对象不再和其他语言(如C)有着相同的结构。不能把c++对象传至(或接受自)其他语言所写的函数。
四、杂项
- 并非所有的base classes设计目的都是多态用途,如标准string和STL容器都不被设计作为base classes使用,更别提多态了。
- 某些class的设计目的是作为bass class使用,但不是为了多态用途。如标准程序库的input_iterator_tag和被设计用来禁止使用默认生成的构造析构等函数的基类。