zoukankan      html  css  js  c++  java
  • C++构造函数和析构函数顺序

    构造函数

       先看看构造函数的调用顺序规则,只要我们在平时编程的时候遵守这种约定,任何关于构造函数的调用问题都能解决;构造函数的调用顺序总是如下:
    1.基类构造函数。如果有多个基类,则构造函数的调用顺序是某类在类派生表中出现的顺序,而不是它们在成员初始化表中的顺序。
    2.成员类对象构造函数。如果有多个成员类对象则构造函数的调用顺序是对象在类中被声明的顺序,而不是它们出现在成员初始化表中的顺序。
    3.派生类构造函数。

    析构函数
        析构函数的调用顺序与构造函数的调用顺序正好相反,将上面3个点反过来用就可以了,首先调用派生类的析构函数;其次再调用成员类对象的析构函数;最后调用基类的析构函数。
        析构函数在下边3种情况时被调用:
        1.对象生命周期结束,被销毁时(一般类成员的指针变量与引用都i不自动调用析构函数);
        2.delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类虚构函数是虚函数时;
        3.对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用。

    virtual析构函数
    下面来说一说为多态基类声明virtual析构函数:
    在C++中,构造函数不能声时为虚函数,这是因为编译器在构造对象时,必须知道确切类型,才能正确的生成对象,因此,不允许使用动态束定;其次,在构造函数执行之前,对象并不存在,无法使用指向此此对象的指针来调用构造函数,然而,析构函数是可以声明为虚函数;C++明白指出,当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义---实际执行时通常发生的是对象的derived成分没被销毁掉。

    class Derive:public Base
    {
    public:
        Derive(){ std::cout<<"Derive::Derive()"<<std::endl; }
        ~Derive(){ std::cout<<"Derive::~Derive()"<<std::endl; }
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        Base* pBase = new Derive();
        delete pBase;

        return 0;
    }

    输出结果是:
    Base::Base()
    Derive::Derive()
    Derive::~Derive()
    Base::~Base()

    由结果可以看出,在父类的虚析构函数有自己的实现时,当调用完子类对象的析构函数结束后,还会调用父类的析构函数。而一般的虚函数都是子类覆盖了父类的,调用完子类方法后不会再调用父类的方法。况且虚析构函数也不能想一般的虚函数一样写成纯虚函数的形式。这一切还是由于析构函数的特殊性决定的。

    构造和析构函数都有着特别的意义,这是与其它函数不同的,并且在一个类层次中析构函数都会被调用,并且调用顺序是有规定的(文章开头已讲),这些是编译器决定的。因此我们必须给出虚析构函数的函数体以供调用。既然调用顺序已定,父类对象的析构函数总是会被调用,所以就没有被子类覆盖之说了。

  • 相关阅读:
    Python3 Selenium自动化web测试 ==> 第十一节 WebDriver高级应用 -- 显示等待 + 二次封装
    Python3 Selenium自动化web测试 ==>FAQ:Unittest测试报告生成文件名加测试完成时间字符串
    Python3 Selenium自动化web测试 ==>FAQ:日期格式和日期字符串格式相互转换
    学习目录
    dotnet学习系列
    Vue.js——60分钟browserify项目模板快速入门
    Vue.js——使用$.ajax和vue-resource实现OAuth的注册、登录、注销和API调用
    Vue.js——vue-resource全攻略
    Vue.js——基于$.ajax实现数据的跨域增删查改
    Vue.js——组件快速入门(下篇)
  • 原文地址:https://www.cnblogs.com/guoxiaoqian/p/3969933.html
Copyright © 2011-2022 走看看