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

笑着哭i 提交于 2019-12-07 07:54:33

   有许多种做法可以记录时间,因此,设计一个TimeKeeper base class和一些derived classes作为不同的计时方法,相当合情合理:

class TimerKeeper{

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

class AtomicClock:public TimeKeeper{...];//原子钟
class WaterClock:public TimeKeeper{...]; //水钟
class WristWatch:public TimeKeeper{...}; //腕表

 当我们指向在程序中使用时间,不想操心时间如何计算等细节,这时候我们可以设计factory(工厂)函数,返回指针指向一个定时对象。Factory函数会"返回一个base class指针,指向新生成的derived class对象":

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

  这里存在一个问题,当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义--实际执行时通常发生的对象的dervied成分没被销毁。

  消除这个问题的做法很简单:给base class一个virtual析构函数。此后删除derived class对象就会如你想要的那般,它就会销毁整个对象,包含所有derived class成分:

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

Timekeeper* ptk = getTimeKeeper();

...

delete ptk;                             

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

   但是如果class 不含virtual函数,通常表示它并不意图做一个base class。当class不企图做一个base class,令其为析构函数往往是一个馊主意。欲实现virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。这份信息通常是由一个所谓vptr(vitual table pointer)指针指出,vptr指向一个由函数指针构成的数组,称为vtbl(virtual table);每一个带有virtual函数的class都有一个相应的vtbl。当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指向的那个vtbl--编译器在其中寻找适当的函数指针。

  有时候令class带一个pure virtual析构函数,可能颇为便利。pure virtual函数导致abstract(抽象)classes--也就是不能被实体化的class。

 

class AWOV
{
public:
    virtual ~AWOV() = 0;            //声明pure virtual析构函数
}

这个class有一个pure virtual函数,所以它是个抽象class,又由于它有个virtual析构函数,所以不用担心析构函数的问题。这里有一个窍门:你必须为这个pure virtual函数提供一份定义:

AWOV:~AWOV();          //pure virtual析构函数的定义

 析构函数的运作方式是:最深层的那个class(most derived)其析构函数最先被调用,然后是每一个base class的析构函数被调用。

 

结论:

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

  classes的设计目的如果不是作为base class使用,或不是为了具备多态性(polymorphic),就不该声明virtual析构函数。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!