派生类(构造函数)中基类的成员变量初始化顺序
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_i
。 m_i
代表 m_a[0]
等于 1
和 m_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_i
与b.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。以上是关于派生类(构造函数)中基类的成员变量初始化顺序的主要内容,如果未能解决你的问题,请参考以下文章