下面的示例说明如何防止派生类被复制.它基于一个基类,其中复制构造函数和副本赋值运算符都被声明为私有的.
class Uncopyable { protected: // allow construction and destruction of derived objects... Uncopyable() {} ~Uncopyable() {} private: // but prevent copying... Uncopyable(const Uncopyable&); Uncopyable& operator=(const Uncopyable&); };
我们可以使用这个类,结合私有继承,使类无法复制:
class derived: private Uncopyable {...};
请注意,类Uncopyable中的析构函数未声明为虚拟.
以前,我了解到
>基类中的析构函数应该是虚拟的.
>非基类中的析构函数不应该是虚拟的.
在此示例中,Uncopyable的析构函数不是虚拟的,而是从它继承.这似乎违背了我以前学到的智慧.
什么时候和为什么在基类中的析构函数不能被定义为虚拟的?
解决方法
如果您可能尝试通过基类型的指针重新分配派生类型的对象,则基类析构函数只需要为虚拟的.因此,如果您只是私有地继承基类,而不是公开地继承,就像在Uncopyable中一样,那么你不需要担心放入一个虚拟析构函数,因为当使用私有继承时,你不能得到一个指针到派生对象并将其存储在指向基本类型的指针中.
另一个例子可能是,如果你使用一个类似这样的类,使类跟踪对象分配的数量,其中,mixin被继承来获取行为,但不被多态地对待:
template <typename T> class Counter { public: Counter() { ++numInstances; } Counter(const Counter&) { ++numInstances ); ~Counter() { --numInstances; } static unsigned getNumInstances() { return numInstances; } private: static unsigned numInstances; } template <typename T> unsigned Counter<T>::numInstances = 0;
更一般来说,当使用静态多态时,您不需要虚拟析构函数,因为您不会使用指向基类型的指针来多态处理这些类.您只使用指向派生类型的指针.
可能还有一些其他情况我没有在这里覆盖,但是这两个(私有继承,mixin类和静态多态)覆盖了虚拟析构函数不需要的大部分空间.