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

Posted

技术标签:

【中文标题】为啥不能在派生类的构造函数初始化列表中初始化基类的数据成员?【英文标题】:Why can't Initialize the data member of base class in the constructor initializer list of derived class?为什么不能在派生类的构造函数初始化列表中初始化基类的数据成员? 【发布时间】:2012-08-07 02:28:14 【问题描述】:

代码就是这样,并且出现错误:“非法成员初始化:'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


【问题讨论】:

Initialize parent's protected members with initialization list (C++) 的可能重复项 在问这个问题之前,我已经搜索过,但没有找到!! 【参考方案1】:

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

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 构造函数以后如何用不同的值重新构造它呢?

【讨论】:

【参考方案2】:

请参阅this answer 以更完整地了解此处发生的情况。基本上,你不能在B的初始化器中初始化A::a,因为按照标准它是不正确的。

【讨论】:

【参考方案3】:

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

很明显,当您构造派生类时,父类成员已经被构造,因此您不能再次重构基成员,这就是您在本示例中尝试通过将其包含在派生类初始化中所做的事情列表。

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

B::B()

    a = 10;

【讨论】:

【参考方案4】:

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

【讨论】:

以上是关于为啥不能在派生类的构造函数初始化列表中初始化基类的数据成员?的主要内容,如果未能解决你的问题,请参考以下文章

C++中,继承时,创建子类对象,能否在子类构造函数初始化列表里调用基类构造函数?

C++基类和派生类的构造函数

阿里笔试题-派生类构造函数 创建顺序

虚函数总结

生成一个派生类对象时,调用基类和派生类构造函数按啥次序

2017.8.23