`
kanwoerzi
  • 浏览: 1635625 次
文章分类
社区版块
存档分类
最新评论

Effective c++学习笔记——条款07:为多态基类声明virtual析构函数

 
阅读更多
Declare destructors virtual in polymorphic base classes
1、为什么要申明虚函数
C++程序设计中通常会存在一个基类有多个派生类型,而基类中的存在的大都是纯虚函数,需要派生类型实现。而这样的情况下,通过使用factory模式返回一个基类型的指针。在C++中明确指出,一个派生类型经过由一个基类型指针被删除,而该基类型带着一个non-virtual析构函数其结果未定义。只会造成一个局部的销毁,即基类型资源被释放,而派生类型造成memory leak,看下面的代码:
图一:不带virtual时输出结果:
图二:带virtual时输出结果:
以上代码和输出结果可以看出,Derived类继承了Base类,并且在heap上申请了内存资源,在它的析构函数中被释放。但由于Base的析构函数是non-virtual,所以根本没有正确释放Derived类型中的ptr指针。
2、virtual 函数实现内部机制
polymorphic(带多态性质的)base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不应该声明virtual析构函数。那么是不是所有的class都加上virtual析构函数以保万一,事实不是如此。如果没有必要,请不要为析构函数加上virtual二字。原因是virtual是有代价的,为了实现virtual函数,类中间必须要增加一个pointer指向虚函数表,这样增大了类的体积。所以没有必要的话,还是不要随意声明virtual的析构函数。普遍的规则是只有当类当中有virtual的函数时,析构函数才声明为virtual。也就是说这个基类是有多态性质(polymorphic)的。
虚函数的实现需要它所在的对象包含额外的信息,这一信息用来在运行时确定本对象需要调用哪个虚函数。通常,这一信息采取一个指针的形式,这个指针被称为“ vptr ”(“虚函数表指针”)。 vptr 指向一个包含函数指针的数组,这一数组称为“ vtbl ”(“虚函数表”),每个包含虚函数的类都有一个与之相关的 vtbl 。当一个虚函数被一个对象调用时,就用到了该对象的 vptr 所指向的 vtbl ,在 vtbl 中查找一个合适的函数指针,然后调用相应的实函数。
请看如下代码,就知道声明virtual函数是要浪费系统资源的。

3、请注意

不过还有一个问题,那就是继承那些不带virtual函数的标准类库的类,比如string类。如果你继承了string类,那么当你使用string的指针释放你的继承类的话,依然存在上面描述的问题,你的继承类没有释放它该释放的空间。因为string没有virtual的析构函数。所以请不要去继承这些并没有virtual析构函数的类。

还有就是STL中的容器通常继承都毫无意义,因为它们也都没有提供virtual析构函数。C++并没有提供像JAVA或者C#的final和sealed这样的约束关键字来禁止某个类型被继承。 并不是每个类型都会被用来做继承用途,也不是每个类型设计出来被用来做为多态用途,所以正确的设计相当重要。

4、纯虚函数实现


从生成的结果我们可以看到有纯虚函数的类是抽象类,不能生成对象,只能派生。

如果他派生的类的纯虚函数没有被改写,那么,它的派生类还是个抽象类。定义纯虚函数就是为了让基类不可实例化化, 因为实例化这样的抽象数据结构本身并没有意义。或者给出实现也没有意义实际上我个人认为纯虚函数的引入 ,为了安全.因为避免任何需要明确但是因为不小心而导致的未知的结果,提醒子类去做应做的实现.。<wbr><br></wbr>

请记住

1、polymorphic(带多态性质的) base classes应该声明一个virtual 析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。

2、Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性质(polymorphically),就不该声明virtual析构函数。

分享到:
评论

相关推荐

    Effective C++ 中文版

    条款07:为多态基类声明Virtual析构函数 条款08:别让异常逃离析构函数 条款09:绝不在构造和析构过程中调用Virtual函数 条款10:令Operator=返回一个referenceto this 条款11:在Operator=中处理“自我赋值” ...

    Effective C++(第三版)

    条款07:为多态基类声明virtual析构函数 declare destructors virtual in polymorphic base classes. 条款08:别让异常逃离析构函数 prevent exceptions from leaving destructors. 条款09:绝不在构造和析构过程中...

    浅谈C++基类的析构函数为虚函数

     在实现多态时, 当用基类指针操作派生类, 在析构时候防止只析构基类而不析构派生类。 2、例子:  (1)、    #include  using namespace std;  class Base{  public: Base() {};  ~Base() {cout &lt;&...

    实验报告模板-实验4:多态程序设计.doc

    实验报告模板——实验4:多态程序设计.doc实验报告模板——实验4:多态程序设计.doc实验报告模板——实验4:多态程序设计.doc实验报告模板——实验4:多态程序设计.doc实验报告模板——实验4:多态程序设计.doc

    java基础——方法的重写、多态+instanceof(csdn)————程序.pdf

    java基础——方法的重写、多态+instanceof(csdn)————程序

    C++经典实例——体现继承和多态

    本资源是用C++开发的,充分体现了面向对象的思想,封装继承多态。

    delphi析构函数的使用

    delphi析构函数的使用,以及窗体的继承,多态。

    C++程序设计课件:4 继承与多态.ppt

    C++程序设计课件:4 继承与多态.ppt

    C++构造和析构的多态

    C++的多态是通过虚表指针来实现的。但是在构造和析构函数中调用虚函数,情况如何呢?是否还能实现多态呢?本文档从内存角度揭示了这其中的多态实现过程。

    c#学习笔记——学习心得

    当某个类的实例被认为不再有效并符合析构条件时,.NET Framework类库的垃圾回收功能就会调用该类的析构函数实现垃圾回收,一个类只能有一个析构函数。一般准则是,除非有迫不得已的原因,不要使用析构函数,而应把...

    Java实验报告——类的继承、多态的应用

    1、实验名称:类的继承、多态的应用 2、代码内容:学生管理类 3、【实验目的】 (1)进一步熟悉抽象类和抽象方法的定义 (2) 进一步掌握集成和多态的实现方式。

    C语言实现对象编程之多态代码.rar

    在面向对象语言C++的实现上,使用了虚函数的方式,虚函数实质上也是指向虚表(virtual table)的一个函数指针。C++虚表方式的本质和包含的各个函数指针的操作数据结构类似。 ———————————————— 版权...

    c++继承与多态,虚函数实例

    简单例子展示虚函数展现的多态特性,更改一处注释就能对比基类是否是虚函数带来的变化

    C++教学课件:继承和多态.ppt

    C++教学课件:继承和多态.ppt

    More Effective C++

    和其前一本兄弟书籍 Effective C++一样,More Effective C++对每一位以C++为开发工具的程序员而言,都必备读物。  继 Effective C++ 之後,Scott Meyers 於 1996 推出这本「续集」。条款变得比较少,页数倒是多了...

    C++:基于多态的职工管理系统

    1、增加重复员工编号的判定 2、增加清除文件时输入错误的错误提示 3、解决员工岗位输入错误导致的程序崩溃

    C++虚函数和多态学习笔记

    C++虚函数和多态学习笔记

    EffectiveCPlusPlus

    多态基类声明virtual析构函数 别让异常逃离析构构函数 不在构造析构过程中调用virtual函数 operator =返回对* this的引用 在operator =中处理自我赋值 复制对象时勿忘其每一个部份 以对象管理资源 在资源管理类中...

Global site tag (gtag.js) - Google Analytics