Effective C++学习笔记总链接
改善程序与设计的55个具体做法学习笔记-每日1条
条款07:为多态基类声明virtual析构函数
【技巧】
带有多态性质base class 应该声明一个virtual 析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual 析构函数。
class 的设计不是作为base class使用,或不是为了具备多态性,就不该声明virtual 析构函数。
base class带有virtual 函数应该声明一个virtual析构函数
【问题】:当base class(non-virtual析构函数)类型的指针指向derived class对象被删除时,实际执行时通常发生的是对象的derived成分没有被销毁。
【后果】: 造成一个诡异的“局部销毁”对象,这可是形成资源泄漏、败坏之数据结构、在调试器上浪费许多时间的绝佳途径。
【办法】:给base class一个virtual析构函数,此后删除derived class 对象,就会销毁整个对象,包括所有的derived class成分。
virtual 函数的目的是通过base class接口处理derived class对象
virtual函数实现
欲实现出virtual函数,对象必须携带某些信息,主要用来在运行期决定哪个virtual函数该被调用。
这份信息通常是由一个所谓vptr(virtual table pointer)指针指出
vptr指针指向一个由函数指针构成的数组,称为vtbl(virtual table)
每一个带有virtual函数的class 都有一个对应的vtbl
当对象调用某一个virtual函数,实际被调用的函数取决于该对象的vptr指针所指的那个vtbl,编译器在其中寻找适合的函数指针。
若class不含virtual函数,则不要声明virtual 析构函数
如果class不含virtual函数,通常表示它不是用做一个base class,令其析构函数为virtual往往是个馊主意。
【后果】
- 对象内存增加,对象内增加vptr指针内存
- 不再具有移植性。该对象也不再和其他语言(如C)内的相同声明有着一样的结构(其他语言没有vptr) ,因此也就不再可能把传递至其他语言所写的函数,除非明确补偿vptr。
技巧:只要当class内含至少一个virtual函数,才为它声明virtual析构函数。
不要企图继承一个标准容器(STL容器)或任何其他“带有non-virtual析构函数”的class,都会出现“局部销毁”。
pure virtual 析构函数
pure virtual 函数导致 abstract(抽象)class,不能被实体化的class,不能为那种类型创建对象。
有时候你希望拥有抽象class,但没有pure virtual 函数,怎么办?
为你希望它成为抽象的那个class声明一个pure virtual析构函数
class AWOV
{
public:
virtual ~AWOV() = 0; // 声明pure virtual析构函数
};
AWOV::~AWOV() { } // pure virtual析构函数的定义
但必须为pure virtual 析构函数提供一份定义。
【原因】:derived class析构函数最先被调用,然后调用base class析构函数。会创建一个对~AWOV的调用动作,所以必须为这个函数提供一份定义。