这就是代码,并且出现错误:“非法成员初始化:'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
}
这就是代码,并且出现错误:“非法成员初始化:'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
}
在调用派生类的构造函数时,必须已经构造了基类。所以已经太晚了。要了解为什么必须这样,请考虑:
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
构造函数以后如何用不同的值重新构造它呢?
有关此处发生的情况的更完整说明,请参阅此答案。基本上,您不能A::a
在 的初始化程序中进行初始化B
,因为根据标准它的格式不正确。
一条更重要的信息 - 请记住,如果一个类没有通过构造函数初始化列表初始化成员对象,那么将在执行基类构造函数中的第一条语句之前调用该成员的默认构造函数。当你使用初始化器时,你实际上在做的是指定一个构造函数来代替默认构造函数。
显然,当您构造派生类时,父类成员已经被构造,因此您不能再次重构基成员,这就是您在本示例中试图通过将其包含在派生类初始化列表中所做的事情。
顺便说一句,如果您只想让派生类能够将A::a的值设置为特定值,那么请改用以下代码:
B::B()
{
a = 10;
}
因为基类可能希望以自己的方式初始化事物。正确的方法是调用初始化列表中的基本构造函数,并让基本 ctor 自行初始化。