条款07:为多态基类声明virtual析构函数
来源:互联网 发布:大麦盒子解除网络限制 编辑:程序博客网 时间:2024/05/07 14:46
今天看了《Effective C++》中关于 virtual 的用法,感觉在平时的使用中还是要注意一下,所以写一些东西把它记录下来。这里写的会比较简单,如果想有更深的了解推荐看原著。
多态在程序编写中是必不可少的,比如我们设计一个 TimeKeeper 作为 base class 来记录时间,派生出 derived class 作为不同的计时方法。
class TimeKeeper {public: TimeKeeper(); ~TimeKeeper();};class AtomicClock: public TimeKeeper { ... }; //原子钟class WaterClock: public TimeKeeper { ... }; //水钟class WristWatch: public TimeKeeper { ... }; //腕表
按照工厂模式的设计理念,我们设计一个函数来获取 TimeKeeper 的指针指向这个计时对象。
TimeKeeper* getTimeKeeper(); //返回一个指针,指向一个TimeKeeper派生类的动态分配对象
factory(工厂)函数有个规矩:被 getTimeKeeper() 返回的对象必须位于 Heap 中。
因此为了避免内存泄漏(很重要),每次获取 TimeKeeper 指针对象后一定要及时的delete掉。
TimeKeeper* ptk = getTimeKeeper(); //同TimeKeeper继承体系获取一个动态分配对象... //运用它delete ptk; //释放它
“依赖客户执行 delete 动作,基本上便带有某种错误倾向。” ——条款13
这里的问题就在于 base class(TimeKeeper)有一个 non-virtual 析构函数。getTimeKeeper返回的指针指向一个 derived class 对象(例如 AtomicClock),而那个对象却经由一个 base class 指针(例如一个 TimeKeeper* 指针)被删除。C++明白指出:
当 derived class 对象经由一个 base class 指针被删除,而该 base class 带着一个 non-virtual 析构函数,其结果未有定义——实际执行时通常发生的是对象的 derived 成分没有被销毁。
其实消除这个问题的做法也很简单:给 base class(TimeKeeper)一个 virtual 析构函数。此后删除 derived class 对象就会销毁整个对象(包括所有 derived class 成分)。
class TimeKeeper {public: TimeKeeper(); ~TimeKeeper();};TimeKeeper* ptk = getTimeKeeper();... delete ptk; //Bingo
当然,如果 class 不包含 virtual 函数,也就意味着它并不想被用作一个 base class 。这时令其析构函数为virtual 往往是一个 bad idea!(具体细节看原著,这里不多说)
因此,许多人的心得是:只有当 class 内含至少一个 virtual 函数,才为它声明 virtual 析构函数。
这也反过来提醒我们:不要试图去继承一个标准容器(不带 virtual 析构函数)或者其他任何“带有 non-virtual 析构函数”的 class!
C++其实也有类似 JAVA 里 Abstract Class ,就是令 class 带一个 pure virtual 析构函数。pure virtual 函数导致 class 不能被实例化。也就是说你不能为那种类型创建对象。
有时候你希望创建一个抽象 class ,然而手上没有任何 pure virtual 函数,怎么办?解决方法就是为你的抽象 class 声明一个 pure virtual 析构函数。
class AWOV { //AWOV="Abstract w/o Virtuals"public: virtual ~AWOV( ) = 0; //声明 pure virtual 析构函数};AWOV::~AWOV() { }; //pure virtual 析构函数的定义
这个 class 有一个 pure virtual 函数,所以它是个抽象 class,又由于他有个 virtual 析构函数,所以不用担心析构函数的问题。
析构函数的运作方式是:最深层派生的那个 class 其析构函数最先被调用,然后是其每一个 base class 的析构函数被调用。编译器会在 AWOV 的 derived classes 的析构函数中创建一个对 ~AWOV 的调用动作,所以必须为这个函数提供一份定义。如果不这样做,连接器会抱怨的。
请记住:
1.polymorphic (带多态性质的)base classes 应该声明一个 virtual 析构函数。如果 class 带有任何virtual 函数,它就应该拥有一个 virtual 析构函数。
2.Classes 的设计目的如果不是作为 base classes 使用,或不是为了具备多态性(polymorphically),就不该声明 virtual 析构函数。
- 条款07:为多态基类声明virtual析构函数
- 条款:07 为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- 条款07 为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数(Declare destructors virtual in polymorphic base classes.)
- 条款7:为多态基类声明VIRTUAL析构函数
- 条款7:为多态基类声明virtual析构函数
- 条款7:为多态基类声明virtual析构函数
- 条款7:为多态基类声明virtual析构函数
- 条款7 为多态基类声明virtual析构函数
- 条款7:为多态基类声明virtual析构函数
- Effective C++学习7 条款07:为多态基类声明virtual析构函数
- Effective c++学习笔记——条款07:为多态基类声明virtual析构函数
- Android开发——内部存储数据(FileIntputStream和FileOutputStream)
- c语言现代设计方法复习(1)
- 小e开发板重新编译刷写测试AT例程全过程
- 美女图片
- 缓冲输入流、缓冲输出流、对象序列化转为byte[]、byte[]转化反序列化为对象
- 条款07:为多态基类声明virtual析构函数
- mac mysql 的下载和安装
- 动态分区的分配策略
- 关于ddx/ddy重建法线在edge边沿上的artifacts问题
- 微信小程序调查报告(四)真的来了
- 诸天至尊小说
- C++ Primer课后练习10.27,10.28
- CentOS5.5下安装Redis
- Leetcode 155 Min Stack