派生类的构造函数/析构函数执行顺序
创造一个子类对象时(new一个子类对象或在栈中构造),先执行父类的构造函数,再执行自身的构造函数。如果子类继承多个父类,则按照继承的顺序从左到右调用父类构造函数(类继承列表中的越靠前的父类,其构造函数越先执行,第一个父类的构造函数首先执行),析构的顺序与构造的顺序相反。
class A : public B ,public C
{
public:
A();
~A();
}
//首先执行B的构造函数,然后执行C的构造函数,最后执行A的构造函数
//析构函数以构造顺序的相反顺序执行
样例
当继承的类都是普通基类或都是虚拟基类的时候,执行顺序为从左往右。
虚拟继承下的构造函数/析构函数顺序
- 首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;
- 执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;
* 注意:虚基类的构造优先于普通基类,且多个虚基类之间也与普通基类之间一样按照从左到右的顺序进行构造(在前面的基类首先构造,最左边的虚基类第一个被构造)。* - 执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;
- 执行派生类自己的构造函数;
析构以与构造相反的顺序执行;
在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。
虚继承下的构造顺序总结
虚基类(即冒号后面的继承列表中含有virtual关键字的类即为虚拟继承的类)优先于普通基类构造,所有虚基类构造完成后,开始构造普通基类,普通基类完成构造后,执行派生类的构造函数之函数体。
虚继承下的析构顺序总结
与构造顺序相反。
虚继承样例
#include <iostream>
using namespace std;
class A
{
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};
class C
{
public:
C(){cout << "C()" << endl;}
~C(){cout << "~C()" << endl;}
};
class D
{
public:
D(){cout << "D()" << endl;}
~D(){cout << "~D()" << endl;}
};
class B: public A, virtual public C, public D //虚拟继承C,普通继承A、D
{
public:
B(){cout << "B()" << endl;}
~B(){cout << "~B()" << endl;}
};
int main(int argc, char const *argv[])
{
B b;
return 0;
}
类的成员是其它类对象-类的构造函数执行其成员的构造函数来构造成员
存在类A和C,以及类B,其中,类B包含了类C和A作为其成员。此时,B并不是继承C、A,但是要在构造函数B()中使用初始化列表来调用C、A的构造函数以构造C、A类型的成员。
#include <iostream>
using namespace std;
class A
{
public:
A(){cout << "A()" << endl;}
~A(){cout << "~A()" << endl;}
};
class C
{
public:
C(){cout << "C()" << endl;}
~C(){cout << "~C()" << endl;}
};
class B
{
public:
B():a(A()), c(C()) {cout << "B()" << endl;} //构造函数调用父类的构造函数,顺序不能影响父类构造函数书序
~B(){cout << "~B()" << endl;}
C c; //父类类型成员
A a; //声明顺序决定构造顺序即父类构造函数执行顺序
};
int main(int argc, char const *argv[])
{
B b;
return 0;
}
样例
当构造函数存在初始化列表时(即构造函数的冒号后面的一串),首先执行初始化列表,再执行本身构造函数体。
特别注意:构造函数的初始化列表中的顺序并不能决定类型成员的构造函数的执行顺序!!
类型成员的构造函数执行顺序由它们在类中定义的顺序来决定。
只要类型C的成员的定义出现在类型A的成员的定义之前,那么不论初始化列表中的顺序,类型C的成员会先于A构造。

本文详细解析了派生类对象创建与销毁时构造函数及析构函数的执行顺序,包括单一继承、多重继承、虚拟继承等多种情况,并通过示例代码说明构造函数初始化列表与成员对象构造顺序的关系。
1959

被折叠的 条评论
为什么被折叠?



