C++类的初始化

构造函数的执行顺序

假设有如下两个类:

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编译通过)

4,249 次阅读

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注