Effective C++读书笔记之七:为多态基类声明virtual析构函数

Item 07: Declare destructors virtual in polymorphic base classes

在C++当中,如果一个derived对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结构未有定义——实际执行时通常发生的是对象的derived成分没被销毁,造成一个诡异的“局部销毁“现象。这会导致资源泄露、数据结构败坏以及令你在调试器上浪费许多时间。

消除这个问题的做法很简单:给base class一个virtual析构函数。那么此后删除derived class对象就会如你想要的那般。

当class不企图被当做base class,令其析构函数为virtual往往是个馊主意。

欲实现出virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。这份信息通常是由一个所谓vptr指针指出。vptr指向一个由函数指针构成的数组,称为vtbl;每一个带有virtual函数的class都有一个相应的vtbl。当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指向的那个vtbl——编译器在其中寻找适当的函数指针。请看下面这个例子:

 class Point
 {
public:
	Point(int xCoord,int yCoord);
	~Point();
private:
	int x,y;
 };

如果Point class内含virtual函数,其对象的体积会增加:在32-bit计算机体系结构中将占用64bits(为了存放两个ints)至96bits(两个ints加上virtual);在64-bit计算机体系结构中将占用64~128bits。为此,为Point添加一个vptr会增加其对象大小达50%~100%!Point对象不再能够塞入一个64-bit缓存器,而C++的Point对象也不再和其他语言(如C)内的相同声明有着同样的结构(因为其他语言的对应物并没有vptr),因此会破坏其移植性。

并非所有的base classes的设计目的都是为了多态用途。例如标准的string和STL容器都不被设计作为base classes使用,更别提多态了。

//云风评注:析构函数的本质源于RAII的编程风格。RAII固然是一种合理的资源回收方案。在所有的资源中,以内存最为特殊。内存不像别的资源那样是以原子方式一个个地使用和回收的,而是从一整块上一点点切分出去,在回收的时候又一块块归还,并以不同的尺寸复用。内存的分配和回收本身就是个复杂的过程,这使得内存管理需要额外的数据空间和执行复杂的算法。许多软件在正常关闭的时候会引起严重的硬盘颠簸就不难理解了。不再使用的内存引用由于管理内存本身的需要又要被访问到,从硬盘的交换分区交换进来,仅仅为了逻辑上释放它们。讽刺的是,大多素对象的析构函数消耗了巨量的CPU时间,仅仅是为了正确地调用其他对象的析构函数,而最终只是释放它共有的一块完整的内存空间。//

请记住:
1.带多态性质的base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。
2.Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性,就不该声明virtual析构函数。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章