对象的构造/析构顺序
- 初始化虚基类,按照继承顺序,从左到右,从最深到最浅。
- 初始化按照继承顺序初始化父类,如果父类还有父类,则递归的初始化父类的父类。
- 初始化虚函数表和虚函数指针。
- 按照声明顺序初始化初始化列表中的成员,如果成员不在初始化列表中,则使用默认初始化构造初始化。
- 执行用户的初始化代码。
从初始化顺序中可以看出两点:1、如果用户在自己的初始化代码中使用了memcpy函数,可能破坏虚函数指针,导致程序运行出错。2、如果在父类的构造函数中调用虚函数,只能执行父类的虚函数,而无法调用子类的虚函数,因为这个时候的虚函数指针指向的是父类的虚函数数,子类的虚函数表还没有构造出来。
#include<iostream>
using namespace std;
class A1{
public:
A1(int val){
cout << "A1()" << endl;
}
~A1(){
cout << "~A1()" << endl;
}
};
class A2{
public:
A2(int val){
cout << "A2()" << endl;
}
~A2(){
cout << "~A2()" << endl;
}
};
class B1 :public A1{
public:
B1():A1(0){
cout << "B1()" << endl;
}
~B1(){
cout << "~B1()" << endl;
}
};
class B2 :virtual public A2{
public:
B2():A2(0){
cout << "B2()" << endl;
}
~B2(){
cout << "~B2()" << endl;
}
};
class C :public B1, public B2{
public:
C():A2(0){
cout << "C()" << endl;
}
~C(){
cout << "~C()" << endl;
}
};
int main(){
C *c = new C();
delete c;
return 0;
}
这个代码主要想说明两件事,1、在虚继承中,虚基类的初始化应该由子类初始化,因为可能存在多个父类继承同一个虚基类的情况,虚基类的初始化会有歧义。2、按照顺序初始化初始化父类,但是会优先初始化虚基类。此外,还有一点值得注意,在多继承中,会有this指针调整的发生。
对象的虚构顺序恰恰和构造顺序相反,这也比较好理解,就像对栈的操作,入栈和出栈的顺序恰好相反。也就是说,析构的顺序为:
- 执行用户的代码。
- 以和声明顺序相反的顺序调用对象成员的析构函数(如果有的话)。
- 重新设置虚函数指针,使其指向子类的虚函数表。
- 和声明顺序相反的循序递归调用父类的析构的函数。
- 以相反的顺序调用虚基类的析构函数。
网友评论