面临的问题是:使用多态时,是由一个基类的指针指向派生类对象,动态绑定的调用派生类的形为函数,当使用完毕时要delete这个对象时,销毁的是基类的那部分成员,而派生类中定义的成员变量没有被销毁。主要原因是这个派生类的析构函数没有被调用。这就会造成资源泄露。例如:
class TimeKeeper { //声明了一个时钟的基类
public:
TimeKeeper();
~TimeKeeper(); //不是virtual
....
};
class AtomicClock: public Timekeeper {...}; //不同的继成类
class WaterClock: public TimeKeeper {...}; //不同的继成类
TimeKeeper* ptk = getTimeKeeper(); //利用工厂模式 这个函数返回一个派生类的对象指针
.... //运用这个指针..
delete ptk; //释放它 这个地方有问题如上所述,会造成资源泄露
解决方法:给base class一个virtual析构函数。就可以销毁所有整个对象,包括所有的derived class成分,例子:
class TimeKeeper { //声明了一个时钟的基类
public:
TimeKeeper();
virtual ~TimeKeeper(); //是virtual
....
};
TimeKeeper* ptk = getTimeKeeper(); //利用工厂模式 这个函数返回一个派生类的对象指针
.... //运用这个指针..
delete ptk; //释放它 这样不仅可以释放base class成分,同时derived class也会释放
原则:任何class只要带有virtual函数都几乎确定应该也有一个virtual析构函数
注意:
1) 如果class不含virtual函数,通常表示它并不意图被用做一个base class。当class不企图被当作base class,令其析构函数为virtual往往是个不好的主意。因为class需要为这个虚函数提供额外的存储空间来维护这个virtual函数
2) 当你试图用一个没有虚函数的类作基类时,需要注意对象的销毁工作有可能引发上面提到的问题
另外的用途:如果你希望一个类为抽象类,可是这个类中又没有pure virtual函数,你可以把析构函数声明为pure virtual。例如:
class AMOV { //抽象类
public:
virtual ~AMOV() = 0; //声明为pure virtual函数
};
这么做可以达到把类变成抽象类的目的,同时也不有担心销毁派生类出现的问题。不过这有一个要求就是必须给出这个函数的定义
AMOV::~AMOV() {} //pure virtual析构函数的定义
析构函数的调用顺序:最深层派生类的析构函数最先调用,然后是每个base class类的析构函数。
总结:
1) polymorphic(带多态性质的)base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。
2) Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数