构造函数的执行顺序
假设有如下两个类:
class Shape
{
public:
Shape()
{
printf("Shape's default constructor!\n");
}
// 注意char *s中的*号和s放在一起,表示定义了一个char的指针
// 因此可以同时定义成如下样子:
// char ch, *s, *msg
// 表示定义了一个ch字符和两个指针
Shape(char *s)
{
printf("Shape's constructor with msg: %s\n", s);
}
Shape(int a)
{
printf("Shape's constructor with parameter(int a).\n");
}
};
class Circle : public Shape
{
public:
Circle()
{
printf("Circle's default constructor!\n");
}
Circle(int a) : Shape("Init Shape Directly")
{
printf("Circle's constrctor with parameter(int a).\n");
}
};
所有子类(Circle)构造函数如果没有显式调用父类(Shape)构造函数时均会调用父类的默认构造函数。
例如:new Circle() 产生的结果是:
Shape’s default constructor!
Circle’s default constructor!
而 new Circle(1) 产生的结果是:
Shape’s constructor with msg:Init Shape Directly
Circle’s constrctor with parameter(int a).
第二种情况已经使用了某一个构造函数初始化父类,此时不再调用默认构造函数。
对数据成员的构造
如果上例中的Circle类写成下面这样:
class Circle : public Shape
{
private:
Shape s;
public:
Circle()
{
printf("Circle's default constructor!\n");
}
Circle(char *msg) : Shape(msg)
{
printf("Circle's default constructor!\n");
}
Circle(int a) : Shape("Init Shape Directly"), s("Init a member object of Circle.")
{
printf("Circle's constrctor with parameter(int a).\n");
}
};
此时涉及到成员对象初始化的情况,如果使用new Circle()来构造,产生的结果是:
Shape’s default constructor!
Shape’s default constructor!
Circle’s default constructor!
第一行是Circle初始化的时候调用Shape的默认构造函数产生的,之后就是Circle自己的初始化,初始化s成员对象,所以又调用了一
次Shape的默认构造函数,最后才调用Circle的初始化函数。
使用Circle的第二个构造函数能够看的更清楚一些:new Circle(“Init parent class directly!”),产生的结果是:
Shape’s constructor with msg: Init parent class directly!
Shape’s default constructor!
Circle’s default constructor!
使用Circle的第三个构造函数,就是显式的初始化成员变量s,例如:new Circle(1) 显示的结果是:
Shape’s constructor with msg:Init Shape Directly
Shape’s constructor with msg:Init a member object of Circle.
Circle’s constrctor with parameter(int a).
因此,可以看到成员对象的初始化顺序是:
初始化父类 -> 初始化子类成员 -> 调用子类构造函数体
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
其中,初始化父类的构造函数选择顺序是:
调用显式构造函数 > 调用默认构造函数
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
简单类型的数据成员的初始化
这个问题要简单得多:
class Circle
{
private:
int r;
Shape *parent;
public:
Circle() : r(10), parent(NULL)
{
}
};
可见,只需要直接将需要初始化的值,放在构造函数的初始化列表当中即可。
(以上程序用GCC编译通过)