Effective C++ 条款07:为多态基类声明virtual析构函数
前面的铺垫有点多= =
我们考虑这样一种情况:有很多种计时方法,比如原子计时,水滴计时等。我们试图抽象出一个基类计时类,然后其他方法的计时器继承这个类。设计如下
class TimeKeeper{
public:
TimeKeeper();
~Timekeeper();
};
class AtomicClock: public TimeKeeper{}; // 原子钟
class WaterClock: public Timekeeper{}; // 水滴钟
class WristWatch: public TimeKeeper{}; // 腕表
这里需要一点设计模式的知识:工厂方法模式。这是一个创建型设计模式,为了简化创建多个同质(继承与同一基类)的问题。这里不细说了,可以先了解一下工厂方法模式。
我们创建了一个工厂函数用于生成这些类的对象
TimeKeeper* getTimeKeeper();
工厂方法返回的是一个基类指针,指向派生类的对象。很显然,这个派生类的对象是被工厂方法new出来的,放在了heap存储区。
那么用户就需要考虑delete掉这个指针的问题。我们试图让用户记住某些一定要执行的操作(delete),这不是一个好的设计,因为用户极可能忘记。
更严重的问题是,这个代码有一个非虚析构函数。在派生类被delete的时候,会调用对象的析构函数。这里我们用的是基类的指针delete,那么基类部分的内存肯定被释放掉了。那派生类的部分被delete了吗?由于基类的析构函数是个非虚的,基类的指针就无法动态绑定到派生类的析构函数上。因此delete基类,只能调用基类的析构函数,无法调用派生类的析构函数。假设我们的派生类里有指针并且动态分配了内存,这就会导致内存泄露
如果我们不希望一个类被继承,最好不要设计一个虚析构函数。因为将函数设置为虚的,C++会多给他整一个虚指针和虚表。这样可能会导致不同机器上的兼容性问题。如无必要,勿增实体。
并非所有的基类设计都是为了多态用途的。这些类就不需要虚的析构函数。

浙公网安备 33010602011771号