《Effective C++》条款14 总是让base class拥有virtual destructor
有时,一个类想跟踪它有多少个对象存在。一个简单的方法是创建一个静态类成员来统计对象的个数。这个成员被初始化为0,在构造函数里加1,析构函数里减1。(条款m26里说明了如何把这种方法封装起来以便很容易地添加到任何类中,“my article on counting objects”提供了对这个技术的另外一些改进)
设想在一个军事应用程序里,有一个表示敌人目标的类:
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派生出来的类(参见条款35及m33)。因为不但要关心敌人目标的总数,也要关心敌人坦克的总数,所以和基类一样,在派生类里也采用了上面提到的同样的技巧:
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; // 坦克对象计数器
};
(写完以上两个类的代码后,你就更能够理解条款m26对这个问题的通用解决方案了。)
最后,假设程序的其他某处用new动态创建了一个enemytank对象,然后用delete删除掉:
enemytarget *targetptr = new enemytank;
...
delete targetptr;
到此为止所做的一切好象都很正常:两个类在析构函数里都对构造函数所做的操作进行了清除;应用程序也显然没有错误,用new生成的对象在最后也用delete删除了。然而这里却有很大的问题。程序的行为是不可预测的——无法知道将会发生什么。
c++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。这意味着编译器生成的代码将会做任何它喜欢的事:重新格式化你的硬盘,给你的老板发电子邮件,把你的程序源代码传真给你的对手,无论什么事都可能发生。(实际运行时经常发生的是,派生类的析构函数永远不会被调用。在本例中,这意味着当targetptr
删除时,enemytank的数量值不会改变,那么,敌人坦克的数量就是错的,这对需要高度依赖精确信息的部队来说,会造成什么后果?)
为了避免这个问题,只需要使enemytarget的析构函数为virtual。声明析构函数为虚就会带来你所希望的运行良好的行为:对象内存释放时,enemytank和enemytarget的析构函数都会被调用。
和绝大部分基类一样,现在enemytarget类包含一个虚函数。虚函数的目的是让派生类去定制自己的行为(见条款36),所以几乎所有的基类都包含虚函数。
如果某个类不包含虚函数,那一般是表示它将不作为一个基类来使用。当一个类不准备作为基类使用时,使析构函数为虚一般是个坏主意。请看下面的例子,这个例子基于arm(“the annotated c++ reference manual”)一书的一个专题讨论。
《Effective C++》条款14 总是让base class拥有virtual destructor的更多相关文章
- Effective C++ 条款14
在资源管理器中小心copying行为 上节是对资源的管理说明.有时候我们不能依赖于shared_ptr或者auto_ptr,所以我们须要自己建立一个资源管理类来管理自己的资源. 比如建立一个类来管理M ...
- Effective C++ -----条款14: 在资源管理类中小心copying行为
复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 普遍而常见的RAII class copying行为是:抑制copying(使用私有继承 ...
- Effective C++ 条款七 为多态基类声明virtual析构函数
class TimeKeeper { public: TimeKeeper(); // ~TimeKeeper(); 错误,此作为一个基类,被继承了.其继承类被delete后,基类被销毁,但继承类可能 ...
- More Effective C++ 基础议题(条款1-4)总结
More Effective C++ 基础议题(条款1-4)总结 条款1:仔细区别pointers和references 如果有一个变量,其目的是用来指向(代表)另一个对象,但是也有可能它不指向(代表 ...
- Effective C++ -----条款18:让接口容易被正确使用,不易被误用
好的接口很容易被正确使用,不容易被误用.你应该在你IDE所有接口中努力达成这些性质. “促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容. “阻止误用"的办法包括建立新类型.限 ...
- [More Effective C++]条款22有关返回值优化的验证结果
(这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回 ...
- More Effective C++ 条款0,1
More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类 ...
- Effective C++_笔记_条款07_为多态基类声明virtual析构函数
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个规则只适用于polymorphic(带多态性质的)base ...
- [Effective C++系列]-为多态基类声明Virtual析构函数
Declare destructors virtual in polymorphic base classes. [原理] C++指出,当derived class对象经由一个由base clas ...
随机推荐
- loading图片制作(没有设计师的情况下,前端同学自己制作loading动图)
svg css gif http://loading.io/
- Linux自动化运维部署+运维
自动化部署及配置(Cobbler/Kickstart) 红帽发布的网络安装服务器套件 Cobbler可以说是一大Linux装机利器,可以快速的建立网络安装环境,据说比Kickstart还要好用. 分布 ...
- build/envsetup.sh中hmm、get_abs_build_var、get_build_var解析
function hmm() { # 打印帮助信息 cat <<EOF Invoke ". build/envsetup.sh" from your shell to ...
- ANDROID 通过监听来电去电,并弹出悬浮窗
要监听android打电话和接电话,有一种的是通过新建一个Receiver继承自BroadcastReceiver. 还有一种也可通过PhoneStateListener来实现.今天就说说后面一种,废 ...
- Default Custom Action Locations and IDs
Default Custom Action Locations and IDs SharePoint 2013 The following ta ...
- Win7系统中MS SQLServer 2005 无法连接
今天重装了一下Win7系统,数据库自然也重新装了一下.谁知道竟然无法连接,使用通用的解决问题方法一一测试: 1.启动数据库主要服务(因为我安装时取消了自动启动),也无法连接: 2.查看,windows ...
- Android简单例子——AlertDialog
最近学习了一段时间的Android,在网上找了些小的Demo,自己模拟这做了下,首先谢谢那些提供例子的朋友 今天主要学习的是简单的Dialog的使用(实现退出对话框)和自定义对话框 1.实现退出对话框 ...
- Object-C 设计类接口
在Object-C中,一个类通常分为两部分,.h头文件和.m实现文件. 类的接口(interface)通常存放在类似ClassName.h的文件中.在这里我们定义实例变量和公用(public)方法. ...
- CSS Text文本格式
Text Color 颜色属性被用来设置文字的颜色. 颜色是通过CSS最经常的指定: 十六进制值 - 如"#FF0000" 一个RGB值 - "RGB(255,0,0)& ...
- wel
欢迎来到mathant.com 这个网站是什么 这个网站是我搭建在阿里云vps上的个人网站.目前的用途是充当个人博客和云存储,当然它的功能不止如此.我会在以后的日子里完善他,希望他能变得更好.目前我在 ...