有许多种做法可以记录时间,因此,设计一个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析构函数。
来源:CSDN
作者:IT呵呵哒
链接:https://blog.csdn.net/qq_34938530/article/details/88259755