派生类(构造函数)中基类的成员变量初始化顺序

Posted

技术标签:

【中文标题】派生类(构造函数)中基类的成员变量初始化顺序【英文标题】:Order of member variables initialization of the base class in the derived class (constructor) 【发布时间】:2017-02-26 21:34:00 【问题描述】:

我是否正确理解了这里的初始化是如何工作的?我将说明步骤:

    基类构造函数被调用。我们输出 0 并增加m_i = 1; 因为m_x 在基类的成员变量中位于m_a 之前,我们要预先递增m_i。我们输出 2 并增加m_i。 我们正在创建一个 A 类型对象的动态数组。对于m_a[0],我们输出 0 并递增m_i;对于 m_a[1],我们 输出 0 并增加 m_im_i 代表 m_a[0] 等于 1m_i 代表 m_a[1] 等于 1。 最后我们移动到派生类的构造函数的主体,我们输出 m_i = 2.

输出是:02002

当我们进入基本构造函数的主体时,我真的不明白为什么m_i 的输出等于2?在第 2 步之后,m_i 不应该等于 3 吗?


源代码

   #include <iostream>

class A

public:
    A(int n = 0)
        : m_i(n)
    
        std::cout << m_i;
        ++m_i;
    

protected:
     int m_i;
;

class B
    : public A

public:
    B(int n = 5) : m_a(new A[2]), m_x(++m_i) std::cout << m_i; 

    ~B()  delete [] m_a;

private:
    A m_x;
    A *m_a;
 
;

int main()

    B b;
    std::cout << std::endl;

    return 0;


【问题讨论】:

您似乎混淆了继承与包容。 @πάνταῥεῖ 哦,男孩,那我一团糟 调试器是解决此类问题的正确工具。 询问 Stack Overflow 之前,您应该逐行逐行检查您的代码。如需更多帮助,请阅读How to debug small programs (by Eric Lippert)。至少,您应该 [编辑] 您的问题,以包含一个重现您的问题的 Minimal, Complete, and Verifiable 示例,以及您在调试器中所做的观察。 这是一个更详细的版本,因此您可以跟随调试器:ideone.com/JjCTxc 我认为您将b.m_ib.a_x.m_i 混淆了 【参考方案1】:

在我解释问题之前,让我先说一下:如果您的对象的初始化非常复杂以至于需要我将要介绍的详细知识,那么请修复那个。使初始化过于复杂对任何人都没有好处。

现在,让我们看看当您通过调用其默认构造函数来构造B 类型的对象时会发生什么。

由于B::A在成员初始化列表中没有提到,所以它会被默认初始化。这将调用A(int),其默认值为0。其结果是将B::A::m_i 初始化为值0,然后输出该值,然后将B::A::m_i 增加到值1。

现在,我们初始化B 的成员。第一个要初始化的成员是B::m_x。用于此操作的成员初始化程序读取并递增 B::A::m_i 的值,这是一个有效初始化的值,在此操作之前恰好为 1。所以在为B::m_x 调用A(int) 之前,B::A::m_i 取值 2。

B::m_x 是通过调用 A(int) 来初始化的,值为 2。它将该值存储在 B::m_x.m_i 中,将其输出,然后将其加一。

接下来,我们初始化B::m_a。成员初始化器通过调用new A[2] 对其进行初始化,这将默认构造2 个A 实例。这些都与您的问题完全无关,因为它们与B::A::m_i 没有任何关系。但它确实输出了两个零。

初始化B::m_a后,我们进入B的默认构造函数本身。在那里,它简单地输出B::A::m_i的值。如果您还记得,最后设置为 2。所以这就是它的输出。

【讨论】:

感谢您的回答。读了几遍之后。一切似乎都清楚了。您的答案中最重要的一段是:现在,我们初始化 B 的成员。要初始化的第一个成员是 B::m_x。此操作的成员初始化程序读取并递增 B::A::m_i 的值,这是一个有效初始化的值,在此操作之前恰好为 1。所以在为 B::m_x 调用 A(int) 之前,B::A::m_i 取值 2。

以上是关于派生类(构造函数)中基类的成员变量初始化顺序的主要内容,如果未能解决你的问题,请参考以下文章

C++中派生类的构造函数怎么显式调用基类构造函数?

C++中如何在子类的构造函数中调用基类的构造函数来初始化基类成员变量

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

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

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

对派生类的初始化