1.构造函数
构造函数的调用顺序如下:
基类构造函数,C++提出的成员初始化列表,对象成员构造函数(非指针类型),派生类本身的构造函数。
2.析构函数调用顺序,
析构函数的调用顺序如下:(析构函数的调用顺序正好和构造函数的调用顺序相反)
派生类本身的析构函数,对象成员的析构函数,基类的析构函数。
这里没有写这个C++提出的成员初始化列表的原因是,他只是负责构造了,构造之后,析构就都是调用对象成员的析构函数了。
这里给出具体的例子看下:
首先这个例子先不给出 C++提出的成员初始化列表,让我们来引入问题,然后把它用C++提出的成员初始化列表 进行解决问题。
#include<iostream>
using namespace std;
class B{
public:
B(){
cout<<"B construct enter"<<endl;
}
~B(){
cout<<"B desconstruct enter"<<endl;
}
B(const B&other){
cout<<"B copy construct enter"<<endl;
}
B& operator=(const B&other){
cout<<"B assign operator enter"<<endl;
B temp=other;
return temp;
}
};
class C{
public:
C(){
cout<< "C construct enter"<<endl;
}
~C(){
cout<<"C desconstruct enter"<<endl;
}
};
class A:public C{
public:
A(B&zhc){
temp=zhc;
cout<<"A construct enter"<<endl;
}
~A(){
cout<<"A desconstruct enter"<<endl;
}
private:
B temp;
};
int main(){
B zyl;
A zhc(zyl);
return 0;
}
代码输出如下图所示
上面的输出我们稍微总结下:
先调用父类的构造,然后调用成员变量的构造,然后调用自己的构造,但是因为在打印之前我们,先用构造函数传进来的参数给,自己的已经默认调用构造函数,完成构造的成员变量赋值了,temp=zhc;所以会调用一次赋值运算符重载。
然后析构顺序正好相反,这个我就不再详细的说了,但是我们发现,这个在效率上有点低,因为我们已经想要对自己的成员变量 B temp 通过这个构造函数进行赋初值,就不想让编译器进行调用默认的构造函数了,也就是你这次的调用没有任何的意义。
那么我们怎么解决这个问题呢,就是用成员列表的初始化,我为了详细而清晰的比较,成员列表初始化和这个成员变量的构造,哪个在前面执行,我又引入了一个,类D,作为A 的成员变量,让其自动调用构造函数初始化,然后我们再加入成员列表的初始化,初始化类A 的成员 B temp,就会解决这个问题,不会先调用 成员的默认构造,而是调用了成员函数的拷贝构造。
#include<iostream>
using namespace std;
class B{
public:
B(){
cout<<"B construct enter"<<endl;
}
~B(){
cout<<"B desconstruct enter"<<endl;
}
B(const B&other){
cout<<"B copy construct enter"<<endl;
}
B& operator=(const B&other){
cout<<"B assign operator enter"<<endl;
B temp=other;
return temp;
}
};
class D{
public:
D(){
cout<< "D construct enter"<<endl;
}
~D(){
cout<<"D desconstruct enter"<<endl;
}
};
class C{
public:
C(){
cout<< "C construct enter"<<endl;
}
~C(){
cout<<"C desconstruct enter"<<endl;
}
};
class A:public C{
public:
A(B&zhc):temp(zhc){
cout<<"A construct enter"<<endl;
}
~A(){
cout<<"A desconstruct enter"<<endl;
}
void Display(){
}
private:
B temp;
D temp1;
};
int main(){
B zyl;
A zhc(zyl);
zhc.Display();
return 0;
}
输入的结果如下:
B construct enter
C construct enter
B copy construct enter
D construct enter
A construct enter
A desconstruct enter
D desconstruct enter
B desconstruct enter
C desconstruct enter
B desconstruct enter
从结果中很容易证明我上面说的结论了。
构造函数的顺序 C(父类) B (成员列表)D (组合的对象)A(派生类自己)
析构函数顺序,A D B C 与构造函数顺序相反。
3.强调一点,如果我们类中的组合成员是另外一个类对象的指针,就不会调用构造函数了。
也就是指针类型和其他基本类型是一致的,如int char 等。
4.就是关于有多个成员变量的情况,成员变量的初始化顺序与,声明顺序有关,声明顺序在前,则先进行初始化,注意一点,就是成员初始化列表的在前,是和一个成员变量自身比的,也就是如果是成员初始化列表的方式,和分成员初始化的方式,和它自己相比。 而不能说是成员初始化列表的成员变量,比 其它非成员列表初始化的都快,主要还是看声明顺序,如果是非成员列表初始化,那么会先进行一次默认的构造,然后还会进行一次赋值运算符重载,成员列表初始化只会进行一次拷贝构造。
#include<iostream>
using namespace std;
class B{
public:
B(){
cout<<"B construct enter"<<endl;
}
~B(){
cout<<"B desconstruct enter"<<endl;
}
B(const B&other){
cout<<"B copy construct enter"<<endl;
}
B& operator=(const B&other){
cout<<"B assign operator enter"<<endl;
// B temp=other;
return *this;
}
};
class D{
public:
D(){
cout<< "D construct enter"<<endl;
}
~D(){
cout<<"D desconstruct enter"<<endl;
}
D(const D&other){
cout<<"D copy construct enter"<<endl;
}
};
class C{
public:
C(){
cout<< "C construct enter"<<endl;
}
~C(){
cout<<"C desconstruct enter"<<endl;
}
};
class A:public C{
public:
A(B&zhc):temp(zhc){
cout<<"A construct enter"<<endl;
}
~A(){
cout<<"A desconstruct enter"<<endl;
}
void Display(){
}
private:
D temp1;
B temp;
};
int main(){
B zyl;
A zhc(zyl);
zhc.Display();
return 0;
}
输出结果如下:
B construct enter
C construct enter
D construct enter
B copy construct enter
A construct enter
A desconstruct enter
B desconstruct enter
D desconstruct enter
C desconstruct enter
B desconstruct enter