C++博客 :: 首页 :: 联系 ::  :: 管理
  163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

常用链接

留言簿(48)

我参与的团队

搜索

  •  

积分与排名

  • 积分 - 369780
  • 排名 - 52

最新评论

阅读排行榜

评论排行榜

设想在一个军事应用程序里,有一个表示敌人目标的类:

class enemytarget

{
public:
  enemytarget() { ++numtargets; }
  enemytarget(const enemytarget&) { ++numtargets; }
  ~enemytarget() { --numtargets; }

  static size_t numberoftargets()
  { return numtargets; }

  virtual bool destroy();         // 摧毁enemytarget对象后
                                              // 返回成功

private:
  static size_t numtargets;     // 对象计数器
};

 

//类的静态成员要在类外定义;
// 缺省初始化为0

size_t enemytarget::numtargets;

敌人的坦克是一种特殊的敌人目标,所以会很自然地想到将它抽象为一个以公有继承方式从enemytarget派生出来的类。因为不但要关心敌人目标的总数,也要关心敌人坦克的总数,所以和基类一样,在派生类里也采用了上面提到的同样的技巧:

class enemytank: public enemytarget {
public:
  enemytank() { ++numtanks; }

  enemytank(const enemytank& rhs)
  : enemytarget(rhs)
  { ++numtanks; }

  ~enemytank() { --numtanks; }

  static size_t numberoftanks()
  { return numtanks; }

  virtual bool destroy();

private:
  static size_t numtanks;         // 坦克对象计数器
};

 

最后,假设程序的其他某处用new动态创建了一个enemytank对象,然后用delete删除掉:

enemytarget *targetptr = new enemytank;

...

delete targetptr

  这样会发生严重问题,因为c++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。实际运行时经常发生的是,派生类的析构函数永远不会被调用。在本例中,这意味着当targetptr 删除时,enemytank的数量值不会改变,那么,敌人坦克的数量就是错的。

如果某个类不包含虚函数,那一般是表示它将不作为一个基类来使用。当一个类不准备作为基类使用时,使析构函数为虚一般是个坏主意。因为它会为类增加一个虚函数表,使得对象的体积翻倍,还有可能降低其可移植性。

所以基本的一条是:无故的声明虚析构函数和永远不去声明一样是错误的。实际上,很多人这样总结:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数。

抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以方法很简单:在想要成为抽象类的类里声明一个纯虚析构函数。

这里是一个例子:

class awov {                // awov = "abstract w/o
                                   // virtuals"
public:
  virtual ~awov() = 0;      // 声明一个纯虚析构函数
};

这个类有一个纯虚函数,所以它是抽象的,而且它有一个虚析构函数,所以不会产生析构函数问题。但这里还有一件事:必须提供纯虚析构函数的定义:

awov::~awov() {}           // 纯虚析构函数的定义

这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。这就是说,即使是抽象类,编译器也要产生对~awov的调用,所以要保证为它提供函数体。如果不这么做,链接器就会检测出来,最后还是得回去把它添上。

注意:如果声明虚析构函数为inline,将会避免调用它们时产生的开销,但编译器还是必然会在什么地方产生一个此函数的拷贝。

posted on 2008-01-22 11:39 sdfasdf 阅读(8438) 评论(4)  编辑 收藏 引用 所属分类: C++

Feedback

# re: Effective C++学习笔记:确定基类有虚析构函数 2008-01-22 17:48 minidxer
这样写点自己的体会并没什么不好的,只是作者在选择发在首页的时候好好考虑一下就是了。
LS的说话还是文明一些比较好  回复  更多评论
  

# re: Effective C++学习笔记:确定基类有虚析构函数 2010-03-30 23:01 kddsly
最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用.
这句话是不是说反了,不是先基类的析构被调用,然后才是派生类的被调用吗?   回复  更多评论
  

# re: Effective C++学习笔记:确定基类有虚析构函数 2011-01-20 10:14 SS
奇怪啊,好像纯虚函数是不能被定义的吧,为什么还可以
awov::~awov() {} // 纯虚析构函数的定义

  回复  更多评论
  

# re: Effective C++学习笔记:确定基类有虚析构函数 2012-01-13 05:19 Jocuri online
好的网站  回复  更多评论
  


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理