C++箴言:多态基类中将析构函数声明为虚拟

C++箴言:多态基类中将析构函数声明为虚拟,第1张

C++箴言:多态基类中将析构函数声明为虚拟,第2张

有许多方法可以跟踪时间的轨迹,因此有必要为不同的计时方法建立一个计时器基类和一个派生类:

班级计时员{
public:
计时员();
~计时员();
...
};

类原子锁:公共计时器{...};
类水钟:公共计时器{...};
级腕表:公共计时器{...};

许多客户只想简单地获得时间,并不关心如何计算时间的细节,因此使用工厂函数(返回指向新创建的派生类对象的基类的指针的函数)来返回指向计时对象的指针:

计时器* getTimeKeeper();//返回一个指针,指向从计时器派生的类
//的动态分配对象

按照工厂函数的约定,getTimeKeeper返回的对象都是建立在堆上的,所以为了避免内存等资源的泄露,最重要的是每一个返回的对象都可以被完全删除。

timer * ptk = getTimeKeeper();//从计时器层次结构中获取动态分配的对象
//的值

...//使用它

删除ptk//释放它以避免资源泄漏

现在我们关注上面代码中一个更基本的缺陷:即使客户做对了一切,也不可能预测程序将如何工作。

问题是getTimeKeeper返回了一个指向派生类对象的指针(比如AtomicClock)。那个对象是通过基类指针(也就是计时器*指针)删除的,这个基类(计时器)有一个非虚析构函数。这是祸根,因为C++指出,当使用基类指针删除一个派生类对象,并且这个基类有一个非虚析构函数时,结果是未定义的。运行时的一个典型后果是对象的派生部分不会被销毁。如果getTimeKeeper返回一个指向AtomicClock对象的指针,那么该对象的AtomicClock部分(即AtomicClock类中声明的数据成员)很可能不会被销毁,AtomicClock的析构函数也不会运行。但是,基类部分(即计时器部分)很可能已经被破坏,这导致了一个奇怪的“部分结构”对象。这是一种泄漏资源、破坏数据结构和消耗大量调试时间的绝妙方法。消除这个问题非常简单:给基类一个虚拟析构函数。因此,当您删除一个派生类对象时,您将得到您所期望的正确行为。整个对象将被销毁,包括所有派生类:

班级计时员{
public:
计时员();
虚拟~计时员();
...
};

timer * ptk = getTimeKeeper();
...
删除ptk//现在行为正常

像TimeKeeper这样的基类除了析构函数一般还包含其他虚函数,因为虚函数的目的是允许派生类定制自己的实现(见第34项)。例如,TimeKeeper可能有一个虚函数getCurrentTime,它在各种派生类中有不同的实现。几乎所有有虚函数的类都应该有虚析构函数。

如果一个类不包含虚函数,这通常表明它不打算用作基类。当一个类不打算成为基类时,将析构函数声明为虚的通常不是一个好主意。考虑一个在二维中表示一个点的类空:

class Point { // a 2D点
public:
Point(int xCoord,int yCoord);
~ Point();
private:
int x,y;
};

如果int占用32位,那么Point对象正好适合64位寄存器。此外,这种Point对象可以作为64位量传递给用其他语言编写的函数,如C或FORTRAN。如果Point的析构函数是虚的,情况就完全不一样了。

虚函数的实现需要对象携带附加信息,这些信息用于确定对象在运行时应该调用哪个虚函数。通常,这种信息是以称为vptr(虚拟表指针)的指针的形式。Vptr指向一个名为vtbl(虚拟表)的函数指针数组,每个包含虚函数的类都与vtbl相关联。当一个对象调用一个虚函数时,实际调用的函数由以下步骤决定:找到对象的vptr所指向的vtbl,然后在vtbl中找到合适的函数指针。

虚拟函数是如何实现的细节并不重要。重要的是,如果Point类包含虚函数,这类对象的大小会增加。在32位架构中,它们将从64位(相当于两个int)增长到96位(两个int加上VPTR);在64位架构中,它们可以从64位增长到128位,因为在这样的架构中,指针的大小是64位。将vptr添加到Point会使其大小增加50-100%!点对象不再适用于64位寄存器。此外,在C++和其他语言(如C)中,Point对象似乎不再具有相同的结构,因为其他语言缺少vptr的对应物。结果就是,点再也不能传入或传出用其他语言编写的函数,除非你为vptr做了明确的对应,这是它自己的实现细节,因此失去了可移植性。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++箴言:多态基类中将析构函数声明为虚拟

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情