1/24/2005

虚析构函数

编译器总是根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候,C++不管这个指针指向一个基类对象还是一个派生类的对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数的代码来释放资源,而没有重载析构函数,那么此时会有资源泄漏。

所以建议的方式是将析构函数声明为虚函数。如果你使用MFC,并且以CObject或其派生类为基类,那么MFC已经为你做了这件事情;CObject的析构函数是虚函数。一个函数一旦声明为虚函数,那么不管你是否加上virtual修饰符,它在所有派生类中都成为虚函数。但是为了理解明确起见,建议的方式还是加上virtual 修饰符。

C++不把虚析构函数直接作为默认值的原因是虚函数表的开销以及和C语言的类型的兼容性。有虚函数的对象总是在对象开始或者末尾的位置(具体位置随编译器而异)包含一个隐含的虚函数表指针成员。对于MFC类CPoint和CSize这样的小型类,增加一个指针成员就增加了很多内存占用,而且使得其内存表示和基类POINT和SIZE不一致。如果两个类的内存表示一致,那么你有时可以安全地把一个类的指针或数组当作另一个类的指针或数组使用。

如果你声明了一个虚析构函数而没有实现它,那么编译器通常会在连接时报告错误——就像其它的虚函数没有实现时一样,但是有的编译器没有检测这个问题,这样的话在对象析构时会造成运行时崩溃。推荐的方案是在析构函数的声明之后,在类声明中嵌入实现。

No comments: