欢迎来到天天文库
浏览记录
ID:1198699
大小:39.00 KB
页数:4页
时间:2017-11-08
《c++箴言:多态基类中将析构函数声明为虚拟》由会员上传分享,免费在线阅读,更多相关内容在应用文档-天天文库。
1、C++箴言:多态基类中将析构函数声明为虚拟 有很多方法可以跟踪时间的轨迹,所以有必要建立一个TimeKeeper基类,并为不同的计时方法建立派生类: classTimeKeeper{ public: TimeKeeper(); ~TimeKeeper(); ...};classAtomicClock:publicTimeKeeper{...};classWaterClock:publicTimeKeeper{...};classWristWatch:publicTimeKeeper{...}; 很多客户只是想简单地取得时间而不
2、关心如何计算的细节,所以一个factory函数——返回一个指向新建派生类对象的基类指针的函数——被用来返回一个指向计时对象的指针: TimeKeeper*getTimeKeeper();//returnsapointertoadynamic-//allyallocatedobjectofaclass//derivedfromTimeKeeper按照factory函数的惯例,getTimeKeeper返回的对象是建立在堆上的,所以为了避免泄漏内存和其他资源,最重要的就是要让每一个返回的对象都可以被完全删除。 TimeKeeper*ptk=
3、getTimeKeeper();//getdynamicallyallocatedobject//fromTimeKeeperhierarchy...//useitdeleteptk;//releaseittoavoidresourceleak现在我们精力集中于上面的代码中一个更基本的缺陷:即使客户做对了每一件事,也无法预知程序将如何运转。 问题在于getTimeKeeper返回一个指向派生类对象的指针(比如AtomicClock),那个对象通过一个基类指针(也就是一个TimeKeeper*指针)被删除,而且这个基类(TimeKeep
4、er)有一个非虚的析构函数。祸端就在这里,因为C++指出:当一个派生类对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,则结果是未定义的。运行时比较有代表性的后果是对象的派生部分不会被销毁。如果getTimeKeeper返回一个指向AtomicClock对象的指针,则对象的AtomicClock部分(也就是在AtomicClock类中声明的数据成员)很可能不会被销毁,AtomicClock的析构函数也不会运行。然而,基类部分(也就是TimeKeeper部分)很可能已被销毁,这就导致了一个古怪的“部分析构”对象。这是一个泄漏资
5、源,破坏数据结构以及消耗大量调试时间的绝妙方法。排除这个问题非常简单:给基类一个虚析构函数。于是,删除一个派生类对象的时候就有了你所期望的正确行为。将销毁整个对象,包括全部的派生类部分: classTimeKeeper{ public: TimeKeeper(); virtual~TimeKeeper(); ...};TimeKeeper*ptk=getTimeKeeper();...deleteptk;//nowbehavescorrectly 类似TimeKeeper的基类一般都包含除了析构函数以外的其它虚函数,因为虚函数的
6、目的就是允许派生类定制实现(参见Item34)。例如,TimeKeeper可能有一个虚函数getCurrentTime,在各种不同的派生类中有不同的实现。几乎所有拥有虚函数的类差不多都应该有虚析构函数。 如果一个类不包含虚函数,这经常预示不打算将它作为基类使用。当一个类不打算作为基类时,将析构函数声明为虚拟通常是个坏主意。考虑一个表现二维空间中的点的类: classPoint{//a2Dpoint public: Point(intxCoord,intyCoord); ~Point(); private: intx,y;};
7、 如果一个int占32位,一个Point对象正好适用于64位的寄存器。而且,这样一个Point对象可以被作为一个64位的量传递给其它语言写的函数,比如C或者FORTRAN.如果Point的析构函数是虚拟的,情况就完全不一样了。 虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数。典型情况下,这一信息具有一种被称为vptr(virtualtablepointer,虚函数表指针)的指针的形式。vptr指向一个被称为vtbl(virtualtable,虚函数表)的函数指针数组,每一个包含虚函数的类都关联
8、到vtbl.当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的vptr指向的vtbl,然后在vtbl中寻找合适的函数指针。 虚函数如何被实现的细节是不重要的。重要的是如果Point类
此文档下载收益归作者所有