Item 7 (多态中基类的虚析构函数)Declare destructors virtual in polymorphic base classes
看评注版的书的确有点吃力,作为一个英语渣,很多单词都要请教谷歌娘。但是细细的看下去,虽然看上去是个简单的问题,但作者想到的东西却如此之多,还是收获良多的。 先把书上最后的总结心得Mark下,再做虚析构函数进行讨论分析:
Polymorphic base classes should declare virtual destructors. If a class has any virtual funtions, it should have a virtual destructor.
在多态的情形下,作为基类应该把析构函数定义为虚。具体来说就是,如果一个类有任何其他虚函数,那么他的析构函数应该也为虚函数。
Classes not designed to be base classes or not designed to be used polymorphically should not declare virtual destructors.
对于一个类,如果在设计时没有要把它作为基类 或者 没有去运用多态机制的想法,那这个类不应该有一个虚析构函数。回到上一点,“如果一个类有任何虚函数,那么他的析构函数应该也为虚函数”,当一个类,具有其他虚函数时就说明了,这个类是被设计作为基类来使用,所以它的虚函数为虚。
一、为什么需要虚析构函数?
书中举了一个TimeKeeper,一个关于时间的类来说明问题。要回答这个问题,首先要讨论c++的多态机制,多态是通过基类的指针或引用去操作派生类,而客户与抽象的基类打交道,而真正具体调用哪个类的方法,实现,都是在运行时确定(晚绑定)。关键在于,我们使用基类的指针或者引用去操作派生类,如果我们去delete一个基类的指针,如果指针是指向一个基类的对象,那没有任何问题。如果基类是指向一个派生类对象呢?在标准c++中这将未定义的行为。而具体会发生什么,我认为要看编译器怎么实现,一般来说这将导致基类部分被destroy,而派生类部分依然存在,这时就产生了内存泄露。而这样的错误经常是很难被发现的。
二、总是把析构函数定义为虚有事可能是个坏主意。
回到一中的讨论,都是在多态的前提下讨论。那如果我们的类并不打算作为一个基类使用和使用多态,虚函数还应该是虚的么?答案当然是:NO!!!
书本通过一个Point,二维坐标来说明。明显对于Point,我们设计的初衷只是把它当做一个结构体来使用,并不打算发展继承层次。其实对于这个问题自己并没有如此之理解,特别是书中提到的移植性问题,没处理过这个问题,也没有这个概念。大致是说,由于虚函数的实现需要保存一个指向虚表虚指针,这使得类膨胀,分别在32位和64位凶环境下进行了讨论,得出的结论是这样会使这个Point类的体积膨胀50%-100%。通常系统会把这个Point对象放到64位的寄存器里面,而在膨胀之后就放不下了,需要做其他额外的工作,影响了效率。在移植性方面,因为其他语言例如:c什么的,是没有虚机制的,也就是没有虚指针,我们就不能把这个类当做struct来使用传给c编写的接口。
三、在使用别人的类库时也应该注意,类是不是有一个虚析构函数!
即使我们明白了徐析构函数的作用,没有虚析构函数的类还是会给我们造成麻烦,那就是在使用别人提供的类库时,试图图从其中派生自己的类!对于STL所有的诸如Sting,map,set,vector....都没有虚析构函数,如果试图从其中派生自己的类就会出现问题。effective c++提到:遗憾的是c++并没有提供一种类似于java,c#拥有的机制去防止这种情况。我们所能做的只有告诉自己别这样做。
The End~~~~~~
找工作很累,身心都,但相信总会见彩虹的