简要描述:
我们知道在C++中,对于某一个对象的构造函数来讲,可以在初始化列表中进行初始化,也可以在函数体内进行初始化,但是这两者是有差别的,下面就进行相关讲解。
测试代码
测试一:
#include<iostream>
using namespace std;
class A {
public:
int x;
public:
A(){cout<<"A default constructor"<<endl;}
A(int x){this->x=x;cout<<"A other constructor"<<endl;}
A& operator=(const A& a) {
cout << "assign operator" << endl;
this->x= a.x;
return *this;
}
A(const A& a) {
this->x=a.x;
cout << "copy constructor" << endl;
}
~A(){cout<<"A destructor"<<endl;}
};
class B {
public:
A a;
int i;
public:
B():i(1){
cout<<i<<endl;
cout << "B constructor function" << endl;
this->a = 1;
cout << "B other Constructor" << endl;
}
B(A &a) {
cout << "B constructor function" << endl;
this->a = a;
cout << "B other Constructor" << endl;
}
~B(){cout<<"B destructor"<<endl;}
};
int main()
{
B b;
return 0;
}
测试二:
#include<iostream>
using namespace std;
class A {
public:
int x;
public:
A(){cout<<"A default constructor"<<endl;}
A(int x){this->x=x;cout<<"A other constructor"<<endl;}
A& operator=(const A& a) {
cout << "assign operator" << endl;
this->x= a.x;
return *this;
}
A(const A& a) {
this->x=a.x;
cout << "copy constructor" << endl;
}
~A(){cout<<"A destructor"<<endl;}
};
class B {
public:
A a;
int i;
public:
B():i(1){
cout<<i<<endl;
cout << "B constructor function" << endl;
this->a = 1;
cout << "B other Constructor" << endl;
}
B(A &a) :i(1){
cout<<i<<endl;
cout << "B constructor function" << endl;
this->a = a;
cout << "B other Constructor" << endl;
}
~B(){cout<<"B destructor"<<endl;}
};
int main()
{
A a;
B b(a);
return 0;
}
测试三:
#include<iostream>
using namespace std;
class A {
public:
int x;
public:
A(){cout<<"A default constructor"<<endl;}
A(int x){this->x=x;cout<<"A other constructor"<<endl;}
A& operator=(const A& a) {
cout << "assign operator" << endl;
this->x= a.x;
return *this;
}
A(const A& a) {
this->x=a.x;
cout << "copy constructor" << endl;
}
~A(){cout<<"A destructor"<<endl;}
};
class B {
public:
int i;
A a;
public:
B():a(1),i(2){
cout<<i<<endl;
cout << "B constructor function" << endl;
cout << "B other Constructor" << endl;
}
~B(){cout<<"B destructor"<<endl;}
};
int main()
{
B b;
return 0;
}
测试结果:
测试一:
测试二:
测试三:
解释
首先,我们要知道的是,初始化列表是在函数体之前执行的。那么在测试一中,我们代码其实相当于首先会执行初始化i为1的操作,然后由于我们没有在初始化列表中初始化A类型的a,此时编译器会在函数体的最开始部分插入A的默认构造函数。则函数体内执行的顺序为:
A a;//产生一个临时对象,调用了A的默认构造函数。
a.A::A(1);//调用A中相关的构造函数。
this->a=a//调用A中的拷贝构造函数。
a.A::~A();//调用A的析构函数,释放该临时对象。
对于测试二,相当于是构造函数体内对比于测试一,少了一个构造函数与一个临时对象的析构函数。
对于测试三,我们可以看到,当我们在初始化列表中对于A进行了初始化时,在函数体内编译器就不会为我们在构造函数体的开头增加A的初始化函数。
总结:
通过上述的分析,我们可以认识到初始化列表是在构造函数体之前执行的,且如果类中的成员包括我们自己定义的类且没有在初始化列表中初始化该类成员,那么编译器就会在构造函数体最开始的地方调用该成员的默认构造函数。