C++中构造函数与析构函数执行顺序

C++中,当定义一个类的对象时,系统会自动的调用该类的构造函数来为对象开辟内存空间和进行初始化工作。

构造函数执行顺序:

       1,先执行父类的构造函数,对父类的数据成员进行初始化。如果父类还有父类,则一直向上寻找,直到最初的基类;如果有多个父类,则构造函数执行的顺序是声明父类时的顺序,而不是初始化列表中的顺序。

       2,再执行内嵌对象成员的构造函数,对对象成员进行初始化。对象成员的执行顺序是是在类中声明时的顺序,而不是初始化列表中的顺序。

       3,最后在执行子类的构造函数,对子类的数据成员进行初始化。

而析构函数的调用包括以下两种情况:

      (1) 当一个对象的生命周期结束时,该对象该被释放,析构函数将被自动调用。

      (2) 若一个对象时使用new运算符动态创建的,在使用delete运算符释放它时,delete会自动调用析构函数。

析构函数执行顺序:

      析构函数执行的顺序和构造函数刚好相反。

      1,先执行子类的析构函数。

      2,再执行对象成员的析构函数

      3,最后执行父类的析构函数


测试例子:

#include<iostream>
using namespace std;

class A {

public:
	A(){cout<<"A-->构造函数"<<endl;}
	~A(){cout<<"A-->析构函数"<<endl;}
};

class B:public A {
public:
	B(){cout<<"B-->构造函数"<<endl;}
	~B(){cout<<"B-->析构函数"<<endl;}
};

class C	
{
public:
	C(){cout<<"C-->构造函数"<<endl;}
	~C(){cout<<"C-->析构函数"<<endl;}
};

class D
: public B
{
public:
	D(){cout<<"D-->构造函数"<<endl;}
	~D(){cout<<"D-->析构函数"<<endl;}
private:
	C c;
};

int main()
{
	A a;
	B b;
	C c;
	D d;
	return 0;
}

测试结果:


virtual修饰的析构函数:

C++中的构造函数不能声明为虚函数;但是析构函数可以声明为虚函数,有时必须声明为虚函数。

C++中的构造函数不能声明为虚函数的原因:

       (1) 创建一个对象的时候,必须要知道对象的实际类型,而虚函数的行为是在运行期间确定实际类型的,创建对象时,由于对象还没有被创建,所以编译器不知道对象的实际类型是什么。

       (2) 由于虚函数的执行要依靠虚函数表,而虚函数表是在构造函数中进行初始化工作的。所以在创建对象时,虚函数表还没有被初始化,所以无法进行。

        当在类的继承中,定义了一个基类的对象指针指向其派生类的对象,并用delete来释放这个指针时,如果基类的析构函数不是virtual类型的,则系统只会调用基类的析构函数,而不会调用派生类的析构函数,而最终导致内存泄露问题。

测试例子:

#include<iostream>
using namespace std;

class A {

public:
	A(){cout<<"A-->构造函数"<<endl;}
	~A(){cout<<"A-->析构函数"<<endl;}
};

class B:public A {
public:
	B(){cout<<"B-->构造函数"<<endl;}
	~B(){cout<<"B-->析构函数"<<endl;}
};

class C	
{
public:
	C(){cout<<"C-->构造函数"<<endl;}
	~C(){cout<<"C-->析构函数"<<endl;}
};

class D
: public B
{
public:
	D(){cout<<"D-->构造函数"<<endl;}
	~D(){cout<<"D-->析构函数"<<endl;}
private:
	C c;
};

int main()
{
	A *a = new D;
	delete a;
	return 0;
}
测试结果:

显然上面的运行结果不是我们想要的,它只调用了基类A的析构函数,而派生类中的析构函数并未调用,即派生类中的内存并没有得到释放,所以会出现内存泄露问题。解决方法是将基类的析构函数定义为virtual类型的即可(为了代码更加清晰,在派生类的析构函数前也加上virtual关键字):

测试例子:

#include<iostream>
using namespace std;

class A {

public:
	A(){cout<<"A-->构造函数"<<endl;}
	virtual ~A(){cout<<"A-->析构函数"<<endl;}
};

class B:public A {
public:
	B(){cout<<"B-->构造函数"<<endl;}
	virtual ~B(){cout<<"B-->析构函数"<<endl;}
};

class C	
{
public:
	C(){cout<<"C-->构造函数"<<endl;}
        virtual ~C(){cout<<"C-->析构函数"<<endl;}
};

class D
: public B
{
public:
	D(){cout<<"D-->构造函数"<<endl;}
	virtual ~D(){cout<<"D-->析构函数"<<endl;}
private:
	C c;
};

int main()
{
	A *a = new D;
	delete a;
	return 0;
}
测试结果:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值