什么时候要用虚析构函数

虚析构函数

在 Effective C++ 中找到了答案。书中说到在 C++ 中,当派生类(derived class)对象由一个基类(base class)指针删除时,若基类有一个非虚函数(non-virtual)的析构函数时,其结果是未定义的——实际执行时通常发生的是对象的派生类部分没有被销毁。例如下面的示例:

#include <iostream>
using namespace std;

class Shape
{
public:
  Shape() {
    cout <<"CRAT: shape" <<endl;
  }

  ~Shape() {
    cout <<"DEST: shape" <<endl;
  }
};

class Player
{
public:
  Player() {
    cout <<"CRAT: player" <<endl;
  }

  ~Player() {
    cout <<"DEST: player" <<endl;
  }
};

class Ball
{
public:
  Ball() {
    cout <<"CRAT: ball" <<endl;  
  }

  ~Ball() {
    cout <<"DEST: ball" <<endl; 
  }

private:
  Shape shape_;
};

class Football : public Ball
{
public:
  Football() {
    cout <<"CRAT: football" <<endl;
  }

  ~Football() {
    cout <<"DEST: football" <<endl;
  }

private:
  Player players_;
};

int main()
{
  Ball *ball = new Football();
  delete ball;
  return 0;
}

结果:

CRAT: shape
CRAT: ball
CRAT: player
CRAT: football
DEST: ball
DEST: shape

可以看到,当基类指针指向派生类对象时,在删除对象时,并没有调用派生类成员对象及派生类自身的析构函数,而只是调用了基类成员对象及基类的析构函数,于是就造成了“局部销毁”对象的现象,从而导致内存泄露,正确的做法是为基类指定一个虚析构函数 。

为了避免上述问题的出现,我们是不是可以为每个类都声明一个虚析构函数呢?考虑如下的示例:
 

class Point
{
public:
    Point(int x, int y);
    ~Point();

private:
    int x_, y_;
};

上述Point类在32-bit机器上所占用的内存空间为8字节。若我们将Point类的析构函数指定为析函数,那么Point类不得不提供一个vptr(即,virtual table pointer)指针,它指向一个由函数指针构成的数组(vtbl, virtal table)。每个带有虚函数的类都有一个相应的vtbl。当对象调用某个虚函数时,实际被调用的函数取决于该对象的vptr所指向的那个vtbl。因此,无端的将所有类的析构函数声明为虚函数也是错误的。

总结:

1.带多态性质的基类应该声明一个虚析构函数,如果类中包含其他虚函数,也应该拥有一个虚析构函数。
2.若类的设计目的不是作为基类使用,或不是为了具备多态性,就不应该声明虚析构函数。
 

什么时候要用虚析构函数?
      通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。
      一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。
原因:
      在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。
那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。
注意:
如果不需要基类对派生类及对象进行操作,则不能定义虚函数(包括虚析构函数),因为这样会增加内存开销。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值