zoukankan      html  css  js  c++  java
  • (C++)浅谈多态基类析构函数声明为虚函数

    主要内容:

    1、C++类继承中的构造函数和析构函数

    2、C++多态性中的静态绑定和动态绑定

    3、C++多态性中析构函数声明为虚函数

    1、C++类继承中的构造函数和析构函数

    在C++的类继承中,

    建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推;

    析构对象时,其顺序正好与构造相反;

    具体参考文章:http://www.cnblogs.com/AndyJee/p/4575385.html

    2、C++多态性中的静态绑定和动态绑定

    对象的静态类型:对象在声明是采用的类型,在编译期确定;

    对象的动态类型:当前对象所指的类型,在运行期决定,对象的动态类型可以更改,但静态类型无法更改。

    静态绑定:绑定的是对象的静态类型,某特性(比如函数)依赖于对象的静态类型,发生在编译期。
    动态绑定:绑定的是对象的动态类型,某特性(比如函数)依赖于对象的动态类型,发生在运行期。

    具体参考文章:http://www.cnblogs.com/AndyJee/p/4575670.html

    3、C++多态性中基类析构函数声明为虚函数

    先来看几段程序例子:

    • 将基类析构函数声明为虚函数
    #include <iostream>
    using namespace std;
    
    
    class Person{
    public:
        virtual ~Person(){  //declare destructor as a virtual function
        cout << "Person::~Person()" << endl;
        }
    };
    
    class Student : public Person{
    public:
        ~Student(){     // virtual or not is OK
            cout << "Student::~Student()" << endl;
        }
    };
    
    int main(){
        Person *pt1 = new Person;
        Person *pt2 = new Student;        // base class pointer point to derived class
        // Student *pt3 = new Person;     // derived class pointer can not point to base class
        Student *pt4 = new Student;
    
        delete pt1;
        cout << "*********" << endl;
        delete pt2;
        cout << "*********" << endl;
        //delete pt3;
        //cout << "*********" << endl;
        delete pt4;
        cout << "*********" << endl;
    
        return 0;
    }
    

    运行结果:

    • 不将基类析构函数声明为虚函数:
    #include <iostream>
    using namespace std;
    
    
    class Person{
    public:
        ~Person(){  //declare destructor as a virtual function
        cout << "Person::~Person()" << endl;
        }
    };
    
    class Student : public Person{
    public:
        ~Student(){     // virtual or not is OK
            cout << "Student::~Student()" << endl;
        }
    };
    
    int main(){
        Person *pt1 = new Person;
        Person *pt2 = new Student;        // base class pointer point to derived class
        // Student *pt3 = new Person;     // derived class pointer can not point to base class
        Student *pt4 = new Student;
    
        delete pt1;
        cout << "*********" << endl;
        delete pt2;
        cout << "*********" << endl;
        //delete pt3;
        //cout << "*********" << endl;
        delete pt4;
        cout << "*********" << endl;
    
        return 0;
    }
    

    运行结果:

    可以看出:

    用基类指针指向派生类时

    在基类析构函数声明为virtual的时候,delete基类指针,会先调用派生类的析构函数,再调用基类的析构函数。

    在基类析构函数没有声明为virtual的时候,delete基类指针,只会调用基类的析构函数,而不会调用派生类的析构函数,这样会造成销毁对象的不完全。

    分析:

    Person *pt2 = new Student;

    pt2的静态类型为Person,而动态类型为Student,

    当析构函数为虚函数时,为动态绑定,delete pt2,会调用动态类型即派生类的析构函数,由于继承关系,也会调用基类的析构函数;

    而当析构函数为非虚函数时,为静态绑定,delete pt2,会调用静态类型即基类的析构函数,而不会调用派生类的析构函数。

    (以上纯属个人理解)

    总结:

    • 应该为多态基类声明虚析构器。一旦一个类包含虚函数,它就应该包含一个虚析构器,因为多态性,必定会有基类调用派生类。

    • 如果一个类不用作基类或者不需具有多态性,便不应该为它声明虚析构器。

    参考文章:

    http://www.cnblogs.com/children/archive/2012/08/13/2636956.html

  • 相关阅读:
    Java高并发24-使用自定义锁生成一个消费模型
    Java高并发连载23-基于AQS实现自定义同步器
    JavaScript连载38-编写评论界面
    Java高并发22-AQS条件变量的支持
    Java高并发21-AQS在共享,独占场景下的源码介绍
    SSH 集成Shiro和EhCache,设置登录超时时间无效解决办法。
    Vue3.0 + Echarts 实现地区人口数量分布展示
    从零开始学VUE之网络模块(Axios)
    从零开始学VUE之VueX(modules)
    从零开始学VUE之VueX(actions)
  • 原文地址:https://www.cnblogs.com/AndyJee/p/4575810.html
Copyright © 2011-2022 走看看