条款7:为多态基类声明virtual析构函数

 

假设,有一个父类:

class TimeKeeper{ public: TimeKeeper(); ~TimeKeeper(); ... };

 

然后假设有很多子类:

class AutomicClock : public TimeKeeper{...};

class WaterClock : public TimeKeeper{...};

class WristWatch : public TimeKeeper {...};

 

然后再假设有一个 factory 函数:

TimeKeeper* getTimeKeeper(); //返回一个指针,指向一个TimeKeeper // 派生类的动态分配对象。

 

为了在使用后销毁它:

TimeKeeper* ptk = getTimeKeeper(); //从TimeKeeper继承体系 //获得一个动态分配对象 ... //运用它 delete ptk; //释放它,避免资源泄露。

 

但是以上方式存在一个根本问题,问题出在getTimeKeeper返回的指针指向一个derived class对象(例如一个AutomicClock),而那个对象却经由一个base class指针(TimeKeeper*)被删除。而目前base class是一个non-virtual函数。在C++中,derived class对象经由一个base class指针被删除,而该base class 带有一个non-virtual析构函数,其结果未有定义。(也就是,derived class成分可能未被销毁:AutomicClock的析构函数也未能被执行。)但是base class会被销毁。这会导致资源泄露,和想自杀。

 

但是你要是像下面这样搞,那就美了:

class TimeKeeper{

public:

TimeKeeper();

virtual ~TimeKeeper(); //这里是关键

.... };

TimeKeeper* ptk = getTimeKeeper();

...

delete ptk;

 

 

任何class只要带virtual函数都几乎确定应该也有一个virtual 析构函数。

 

如果class不带有virtual函数,说明它不像做base class。当class不企图做一个base class函数的时候,令其析构函数为virtual 往往是个馊主意:

 

想要实现virtual函数,对象必须携带某些信息,主要用来在运行期决定哪个virtual函数该被调用。这份信息通常是一个所谓vpt(virtual table pointer)指针指出。vptr指向一个 由函数指针构成的数组,称为vtbl(virtual table)。每一个带有virtual的class都有一个相应的vtbl,实际被调用的函数却决于该对象的vptr所指的那个vtbl----编译器在其中寻找适当的函数指针。

 

所以含有virtual函数会增加class的体积,所以C++的class对象也就不再和其他语言(如C)声明一样有一样的结构。因此也就不再可能把它传递到其他语言所写的函数,不再具有移植性。

 

当继承non-virtual析构函数class,也是会有问题的。

 

class SpecialString : public std::string //non-virtual 析构函数 { ... };

 

当程序中无意将一个 pointer-to-spectialString转换为一个pointer-to-string。然后将转换所得的那个string指针delete掉,就会出问题:

 

SpectialString* pss = new SpecialString("Impending Doom"); std::string* ps; ... ps = pss; //specialString* => std::string* ... delete ps; //specialString 析构函数没被调用

 

 

 

当希望把class做成一个抽象类,不能被构造对象,所以需要提供一个纯虚函数。但是手上也不知道这里要搞个什么纯虚函数的时候。定义析构函数为纯虚函数。

 

class AWOV { public: virtual ~AWOV() = 0; }; AWOV : ~AWOV() { } //pure virtual 定义

 

析构函数的运作顺序是,最深层派生那个析构函数最先被调用,然后是每一个base class 的析构函数被调用。编译器会在AWOV的derived classes的析构函数中创建一个对~AWOV的调用动作,所以你必须为这个函数提供共一份定义,不然连接器会不高兴。

 

 

多态性质的base classes应该声明一个virtual 析构函数。如果class带有任何virtual函数,它就应该有一个virtual 析构函数。

Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性质,就不该声明virtual 函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值