zoukankan      html  css  js  c++  java
  • 基类中的虚析构函数

    转自:http://glatue.com/category/basic-knowledge/

    场景

    如果一个类会被作为基类,那么基类的析构函数最好声明为虚函数。

    原因是为了避免下面这样的操作,造成派生类的析构函数不能被调用。

    Base *d = new Drived();
    delete d; //如果Base类中的析构函数是非虚的,那么此delete操作只会调用Base的析构函数,而不会调用Drived的析构函数。

    把Base的析构函数定义成虚函数,则能够在上面的delete操作中调用到Drived的析构函数

    底层原理

    首先明白以下几点:
    1. 如果Base的析构函数声明为虚函数,则Drived的析构也会是虚函数(即使不定义为virtual),并且编译器会把Drived的析构函数当做是Base的析构函数的一个实现。
    2. 如果Drived的析构函数被调用,则Base的析构函数会在之后也会被调用到。

    那么我们来看看当Base的析构函数被定义为虚函数以后,会发生什么?

    1. 当 new Drived() 时

    Base被创建,并且创建自身的虚函数表,表中指针指向Base的析构函数

    Drived基于Base被创建,并在Base的虚函数表上进一步的修改,将表中指向Base的析构函数指针指向自身的析构函数位置。

    那么此时,Drived中的虚函数表中的析构函数指针,指向自身的析构函数。

    2. 当 Base *d = new Drived() 时

    编译器会把new Drived() 产生的对应的内存位置当做Base来处理(此时Drived虚函数表中的指针并没有改变)

    3. 当 delete d 时

    此时会去调用析构函数。
    此时d的类型是Base,而Base的析构函数是虚函数,所以需要去虚函数表里找,而此时,虚函数表里析构函数的指针指向的是Drived的析构函数,所以调用析构函数时实际上调用了Drived的析构函数。
    而Base是Drived的基类,所以调用完Drived的析构函数后,会自动调用Base的析构函数。

    4. 那么这样一来

    无论delete谁,都会调用到最“子”的对象的析构函数,进而调用到所有父类的析构函数。就避免了子类析构不被调用的问题。

    验证的代码

    class Base
    {
    public:
        Base(){cout << "Base" << endl;};
        virtual ~Base(){cout << "Base -" << endl;};
        
    };
    
    class Drived : public Base
    {
    public:
        Drived(){cout << "Drived" << endl;};
        ~Drived(){cout << "Drived -" << endl;};
    
        
    };
    
    int main()
    {
        Base *d = new Drived();
        delete d;
        return 0;
    }
    

    输出

    Base
    Drived 
    Drived -
    Base -
    
  • 相关阅读:
    Leetcode 811. Subdomain Visit Count
    Leetcode 70. Climbing Stairs
    Leetcode 509. Fibonacci Number
    Leetcode 771. Jewels and Stones
    Leetcode 217. Contains Duplicate
    MYSQL安装第三步报错
    .net 开发WEB程序
    JDK版本问题
    打开ECLIPSE 报failed to load the jni shared library
    ANSI_NULLS SQL语句
  • 原文地址:https://www.cnblogs.com/demian/p/6538210.html
Copyright © 2011-2022 走看看