为什么不能在派生类的构造函数初始化列表中初始化基类的数据成员?

时间:2012-08-07 02:28:15

标签: c++ inheritance constructor initializer-list

这样的代码,并带有错误:“非法成员初始化:'a'不是基础或成员”,错误信息的含义是什么,为什么??

class A{
public:
int a;
};
class B:public A{

public:
B();
};

B::B():a(10){    // put  "a(10)" into the constructor body is right

}

4 个答案:

答案 0 :(得分:8)

当调用派生类的构造函数时,必须已经构造了基类。所以现在已经太晚了。要了解为什么必须这样,请考虑:

class Base
{
    public:
    int i;
    Base(int q) : i(q) { ; }
};

class Middle : public Base
{
    public:
    Middle() : Base(2) { printf("i=%d\n", i); }
};

class Derived : public Middle
{
    public:
    Derived() : i(3) { ; }
}

现在,想一想。 Middle构造函数必须在Derived构造函数之前运行。 Middle构造函数确保i为2.那么Derived构造函数后来如何使用不同的值重新构造它?

答案 1 :(得分:2)

有关此处发生的更详尽的解释,请参阅this answer。基本上,您无法在A::a的初始化程序中初始化B,因为它根据标准格式不正确。

答案 2 :(得分:0)

因为基类可能想以自己的方式初始化事物。正确的方法是调用初始化列表中的基础构造函数,并让base ctor初始化自己。

答案 3 :(得分:0)

一个更重要的信息 - 请记住,如果类没有通过构造函数初始化列表初始化成员对象,那么在执行基类构造函数中的第一个语句之前,将调用该成员的默认构造函数。当你使用初始化器时,你实际在做的是指定一个构造函数来使用默认构造函数的INSTEAD。

显然,当您构造派生类时,父类成员已经构建,因此您无法再次重构基本成员,这是您在此示例中尝试通过将其包含在派生类初始化中而执行的操作列表。

顺便说一句,如果你想要的是让派生类能够将 A :: a 的值设置为特定值,那么请改用以下代码:

B::B()
{
    a = 10;
}