一、先看一个简单的例子:
class B
{
public:
B(){cout<<"B constructor"<<endl;}
private:
int m;
int n;
};
int _tmain(int argc, _TCHAR* argv[])
{
B b1;
system("pause");
return 0;
}
完成b1对象的构造前,它会先构造类的数据成员(此处为m和n),然后再进入到类B的构造函数,所以显示的结果如下:
B constructor
请按任意键继续. . .
为了显示更清晰,我们增加一个类A,将类B中的数据成员m和n改为类A的对象a1、a2。
class A
{
public:
A(){cout<<"A default constructor"<<endl;}
A(int n){cout<<"A int constructor, n = "<<n<<endl;}
};
class B
{
public:
B(){cout<<"B constructor"<<endl;}
private:
A m;
A n;
};
显示结果为:
A default constructor
A default constructor
B constructor
请按任意键继续. . .
二、上面的还是比较简单的,若考虑“成员初始化列表”呢
class A
{
public:
A(){cout<<"A default constructor"<<endl;}
A(int n){cout<<"A int constructor, n = "<<n<<endl;}
};
class B
{
public:
B():a1(2){a2=3;cout<<"B constructor"<<endl;}
private:
A a1;
A a2;
};
int _tmain(int argc, _TCHAR* argv[])
{
B b1;
system("pause");
return 0;
}
结果:
A int constructor, n = 2
A default constructor
A int constructor, n = 3
B constructor
请按任意键继续. . .
分析看看顺序,
1. 构造成员变量a1,而a1通过成员初始化变量赋值为2了,所以调用类A的构造函数A(int n);
2. 构造成员变量a2,没有初始化,所以直接调用A();
3. 进入类B的构造函数,运行赋值语句“a2=3”,此时会通过A(int n)构造一个临时的对象,然后再拷贝给a2;
4. 输出B constructor;
三、再加大难度,增加类的继承
#include "stdafx.h"
#include<iostream>
using namespace std;
class Z
{
public:
Z(){cout<<"Z default constructor"<<endl;}
Z(int n){cout<<"Z int constructor, int n = "<<n<<endl;}
};
class A
{
public:
A()
{
y=1;
cout<<"A constructor"<<endl;
}
Z x;
Z y;
};
class B : public A
{
public:
B():n(3),m(2)
{
cout<<"B constructor"<<endl;
}
Z m;
Z n;
};
int _tmain(int argc, _TCHAR* argv[])
{
B b1;
system("pause");
return 0;
}
结果如下:
Z default constructor
Z default constructor
Z int constructor, int n = 1
A constructor
Z int constructor, int n = 2
Z int constructor, int n = 3
B constructor
请按任意键继续. . .
其实,也很容易分析,需要明确一点,派生类对象构造前,会先构造基类的对象,所以可以分成两部分来看:
1. 基类A对象的创建
1) 构造成员变量x,调用Z();
2) 构造成员变量y,调用Z();
3) 进入A(),运行赋值语句“y=1”,此时会通过Z(int n)构造一个临时的对象,然后再拷贝给y;
4) 输出A constructor
2. 派生类B对象的创建
1) 构造成员变量m,而m通过成员初始化变量赋值为2了,所以调用类Z的构造函数Z(int n);
2) 构造成员变量n,而n通过成员初始化变量赋值为3了,所以调用类Z的构造函数Z(int n);
3) 进入进入B(),输出B constructor
现在,大家应该对对象创建时各成员的构造顺序有一定的了解了吧,析构函数调用的顺序与构造函数相反,此处就不展开分析了,有兴趣的同学可以自己去实践实践。