构造函数与析构函数的调用顺序

1、构造函数的调用顺序
基类构造函数、对象成员构造函数、派生类本身的构造函数
2、析构函数的调用顺序
派生类本身的析构函数、对象成员析构函数、基类析构函数(与构造顺序相反
析构函数在下边3种情况时被调用:
1.对象生命周期结束,被销毁时(一般类成员的指针变量与引用都i不自动调用析构函数);
2.delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类虚构函数是虚函数时;
3.对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用。

#include "iostream"
using namespace std;
class Base
{
public:
    Base(){ std::cout<<"Base::Base()"<<std::endl; }
    ~Base(){ std::cout<<"Base::~Base()"<<std::endl; }
};

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

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

class Derive1:public Base1
{
private:
    Derive m_derive;//声明一个Derive类的对象m_derive
public:
    Derive1(){ std::cout<<"Derive1::Derive1()"<<std::endl; }
    ~Derive1(){ std::cout<<"Derive1::~Derive1()"<<std::endl; }
};

int main()
{
    Derive1 derive;
    return 0;
}

这里写图片描述
构造函数的调用顺序是;首先,如果存在基类,那么先调用基类的构造函数,如果基类的构造函数中仍然存在基类,那么程序会继续进行向上查找,直到找到它最早的基类进行初始化;如上例中类Derive1,继承于类Base与Base1;其次,如果所调用的类中定义的时候存在着对象被声明,那么在基类的构造函数调用完成以后,再调用对象的构造函数,如上例中在类Derive1中声明的对象Derive m_derive;最后,将调用派生类的构造函数,如上例最后调用的是Derive1类的构造函数。

包含对象成员的类的构造与析构顺序

class A  
{  
public:  
    A()  
    {  
        cout << "A's constructor." << endl;  
    }  
    ~A()  
    {  
        cout << "A's destructor." << endl;  
    }  
};  

class B  
{  
public:  
    B()  
    {  
        cout << "B's constructor." << endl;  
    }  
    ~B()  
    {  
        cout << "B's destructor." << endl;  
    }  
};  

class C  
{  
private:  
    B bInC;  
public:  
    C()  
    {  
        cout << "C's constructor." << endl;  
    }  
    ~C()  
    {  
        cout << "C's destructor." << endl;  
    }  
    A aInC;  
};  

class D:public C  
{  
public:  
    D()  
    {  
        cout << "D's constructor." << endl;  
    }  
    ~D()  
    {  
        cout << "D's destructor." << endl;  
    }  
    A aInD;  
private:  
    B bInD;  
};  

int main(void) {  
    D d;  
    return 0;  
}  

输出结果:

B's constructor.  
A's constructor.  
C's constructor.  
A's constructor.  
B's constructor.  
D's constructor.  
D's destructor.  
B's destructor.  
A's destructor.  
C's destructor.  
A's destructor.  
B's destructor.  

分析如下:
(1)存在继承关系时,先执行父类的构造函数,再执行子类的构造函数;
(2)当一个类中含有对象成员时,在启动本类的构造函数之前,先分配对象空间,按对象成员的声明顺序执行他们各自的构造函数,再继续执行本类的构造函数;
(3)对于非静态的局部对象,他们的析构函数的执行顺序与构造函数相反。
在本程序中:
(1)执行main(),需要创建一个对象d,所以,需要执行D的构造函数。而D继承自C,所以先要执行C的构造函数;
(2)而在C中存在对象成员bInC和aInC,所以,在C的构造函数执行之前,先按声明顺序执行B和A的构造函数,然后执行C的构造函数
(3)轮到构造d了,但是D中有对象成员aInD和bInD,所以,在D的构造函数执行之前,先按声明顺序执行A和B的构造函数,最后,执行D的构造函数;
(4)以上所有对象的析构函数以与构造函数的执行顺序相反的顺序执行。

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

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

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

int main()
{
    Base* pBase = new Derive();
    //这种base classed的设计目的是为了用来"通过base class接口处理derived class对象"
    delete pBase;
    return 0;
}

运行结果
从上面的输出结果可以看出,析构函数的调用结果是存在问题的,也就是说析构函数只作了局部销毁工作,这可能形成资源泄漏败坏数据结构等问题;那么解决此问题的方法很简单,给base class一个virtual析构函数;

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

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;
}

运行结果
由此还可以看出虚函数还是多态的基础,在C++中没有虚函数就无法实现多态特性;因为不声明为虚函数就不能实现“动态联编”,所以也就不能实现多态啦!

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值