Effective C++ 07:为多态基类声明virtual析构函数

        先上结论:
         1、带有多态性质的基类,应该声明一个 virtual 析构函数。如果类带有任何 virtual 函数,它就应该有一个 virtual 析构函数。
         2、类的设计目的如果不是作为 base class 使用,或不是为了具备多态性,就不该声明 virtual 析构函数。

举一个工厂模式的例子:
   
   
class TimeKeeper {
public:
TimeKeeper();
~TimeKeeper();
};
 
class AtomicClock : public TimeKeeper
{
//原子钟
};
 
class WristWatch : public TimeKeeper
{
//腕表
};
先定义一个基类 TimeKeeper 和它的派生类 AtomicClock 和 WristWatch,设计一个工厂函数(工厂模式),返回指针指向一个计时对象。
   
   
TimeKeeper* getTimeKeeper()
{
TimeKeeper* t_keeper = NULL;
switch(type)
{
case 1:
t_keeper = new AtomicClock();
break;
case 2:
t_keeper = new WristWatch();
break;
default:
break;
}
return t_keeper;
}
         在该函数中,我们 new 了一个指针,为了防止内存泄露,在使用完毕的时候一定要delete:
         “依赖客户端执行 delete 动作,基本上便带有某种错误的倾向”!
         如何理解这句话呢?getTimeKeeper 函数返回的指针类型是基类的,但指针却是指向一个派生类的对象,并最终要经由一个基类指针被删除,基类的析构函数是 non-virtual 的,这就导致在实际的执行中,对象中基类的部分被析构,但是派送类独有的部分却没有!这种情况被称为“局部销毁”对象,很容易造成内存泄露。
         所以我们应该将基类的析构函数声明为 virtual 函数: virtual ~ TimeKeeper(); 确保在调用析构函数的时候,子类的析构函数可以“覆盖”父类的析构函数,从而完整的析构整个对象。

         但是,如果一个 类,在设计的时候并不是为了作为 base class 来使用,或着说不是为了具备多态性,那么就不该将析构函数声明为 virtual 函数(这种情况下其他的成员函数也都不应该被声明为 virtual 函数)。
         这是从代码的可移植性角度总结的做法。
   
   
class Point {
public:
Point();
~Point();
private:
int32_t a, b;
};
         这样一个类,它的一个对象可以放入一个64位的寄存器,或者作为一个“64位长度的量”传递。
          但如果这个类有一个 virtual 函数,那么它的对象必须携带更多的信息,用来在运行时期决定哪一个 virtual 函数该被调用。为了保存这些信息,我们需要一张虚表(vtbl)来保存函数的指针,相应的,类 Point 里要增加一个虚表指针 vptr 来指向这张虚表。这样的话,类需要的空间就是 96bits,那么在传递类的对象的时候,就不能把它当做“64bits的量”,要新增很多细节的实现。因此不再具有移植性。
         所以,如果一个类不需要具备多态性,那么就不要为它声明 virtual 函数。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值