zoukankan      html  css  js  c++  java
  • 【C++】为多态基类声明virtual析构函数

      来自《Effective C++》条款07:为多态声明virtual析构函数

      当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义——实际执行时通常发生的是对象的derived成分没被销毁,而其基类成分通常会被销毁,于是造成了一个诡异的“局部销毁”对象。

      解决这个问题的做法很简单:给base class一个virtual析构函数。此后删除derived class对象就会如你想要的那般销毁整个对象。

      当class不企图被当作base class,令其析构函数为virtual往往是个馊主意。许多人的心得是:只有当class内含至少一个virtual函数,才能为它声明virtual析构函数。

      有时候令class带一个pure virtual析构函数,可能颇为遍历,pure virtual函数导致abstract classes——也就是不能被实体化的class。也就是说不能为那种类型创建对象。然而当你希望拥有抽象class,但手上没有任何pure function时就可以将把希望抽象成的那个class声明为一个pure virtual析构函数。下面是个例子:

    class AWOV {
     public:
        virtual ~AWOV() == 0;
    };

      这个class有一个pure virtual函数,所以它是一个抽象class,又由于它有个virtual析构函数,所以你不必担心析构函数的问题。然而这里有个窍门:你必须为这个pure virtual析构函数提供一份定义:

    AWOV::~AWOV() {}

      析构函数的运作方式是,最深层派生的那个class其析构函数最先被调用,然后是其每一个base class的析构函数被调用。编译器会在AWOV的derived classes的析构函数中创建一个对~AWOV的调用动作,所以你必须为这个函数提供一份定义。如果不这样做,连接器会发出抱怨。  

     

    请记住:

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

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

      要分析为什么没有将基类的析构函数声明为virtual,只有基类部分会被销毁呢?这要首先明白C++中的名字查找与继承。理解函数调用的解析过程对于理解C++的继承至关重要,假设我们调用p->mem()(或者obj.mem()),则依次执行以下4个步骤:

      1.首先确定p(或obj)的静态类型。因为我们调用的是一个成员,所以该类型必然是类类型。

      2. 在p(或obj)的静态类型对应的类中查找mem。如果找不到,则依次在直接基类中不断查找直到到达继承链的顶端。如果找遍了该类及其基类仍然找不到,则编译器将报错。

      3. 一旦找到了mem,就进行常规的类型检查以确认对于当前找到的mem,本次调用是合法的。

      4. 假设调用合法,则编译器将根据调用的是否是虚函数而产生不同的代码:

      ——如果mem是虚函数且我们是通过引用或指针进行进行的调用,则编译器产生的代码将在运行时确定到底运行该虚函数的哪个版本,一句是对象的动态类型。

      ——如果mem不是虚函数或者我们是通过对象(而非引用或指针)进行的调用,则编译器将产生一个常规函数调用。

      

      即

      通过对象调用虚函数时,调用哪个类的函数取决于对象的类型。对象类型是基类时,就调用基类的函数;对象类型是子类时,就调用子类的函数。

      使用指针访问非虚函数时,编译器根据指针本身的类型决定要调用哪个函数,而不是根据指针指向对象类型。

      使用指针访问虚函数时,编译器根据指针所指对象的类型决定要调用哪个函数,而与指针本身类型无关。

      可以看到如果我们将基类的指针指向动态分配的子类对象,而基类的析构函数没有声明为虚函数,那么按照名字查找就不会调用到派生类的析构函数。

    参考资料:

      1. 《Effective C++ 》第三版 电子工业出版社

      2. 《C++ Primer》第五版 电子工业出版社 15.6

  • 相关阅读:
    .net core读取appsettings.config中文乱码问题
    vs2017错误:当前页面的脚本发生错误
    VS Code中无法识别npm命令
    Visual Studio报错/plugin.vs.js,行:1074,错误:缺少标识符、字符串或数字
    记录一次在生成数据库服务器上出现The timeout period elapsed prior to completion of the operation or the server is not responding.和Exception has been thrown by the target of an invocation的解决办法
    Java集合框架
    java hash表
    Java Dictionary 类存储键值
    java数据结构 栈stack
    java封装
  • 原文地址:https://www.cnblogs.com/vincently/p/4755930.html
Copyright © 2011-2022 走看看