从派生类初始化列表调用基类构造函数的顺序
struct B {
int b1, b2;
B(int, int);
};
struct D : B {
int d1, d2;
// which is technically better ?
D (int i, int j, int k, int l) : B(i,j), d1(k), d2(l) {} // 1st Base
// or
D (int i, int j, int k, int l) : d1(k), d2(l), B(i,j) {} // last Base
};
上面只是一个伪代码。实际上,我想知道调用基本构造函数的顺序重要吗?
是否存在由以下原因引起的不良行为(尤其是极端情况)有任何案例吗?我的问题更多的是技术方面,而不是编码风格。
struct B {
int b1, b2;
B(int, int);
};
struct D : B {
int d1, d2;
// which is technically better ?
D (int i, int j, int k, int l) : B(i,j), d1(k), d2(l) {} // 1st Base
// or
D (int i, int j, int k, int l) : d1(k), d2(l), B(i,j) {} // last Base
};
Above is just a pseudo code. In actual, I wanted to know that does the order of calling base constructor matter?
Are there any bad behaviors (especially corner cases) caused by any of the cases? My question is on more technical aspect and not on coding styles.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您在问题中引用的顺序不是“调用基本构造函数的顺序”。事实上,你不能调用构造函数。用户不能调用构造函数。只有编译器才能调用构造函数。
您可以做的是指定初始值设定项。在这种情况下(构造函数初始值设定项列表),您正在为某个较大对象的子对象指定初始值设定项。指定这些初始值设定项的顺序并不重要:编译器将按照语言规范定义的非常特定的顺序调用构造函数,而不管您指定初始值设定项的顺序如何。始终首先调用基类构造函数(按照基类在类定义中列出的顺序),然后调用成员子对象的构造函数(同样按照这些成员在类定义中列出的顺序)。
(当涉及到虚拟基类时,这条规则有一些特殊之处,但我决定不将它们包含在这里。)
至于不良行为......当然,这里存在潜在的“不良行为”。如果您假设初始化的顺序取决于您在构造函数初始值设定项列表中使用的顺序,那么当您发现编译器完全忽略该顺序并使用它自己的顺序(声明)代替。例如,此代码的作者
可能期望首先初始化
a
,然后b
从接收
,但实际上这不会发生,因为5
的初始值ab
在a
之前初始化。The order you refer in your question is not the "order of calling base constructor". In fact, you can't call a constructor. Constructors are not callable by the user. Only compiler can call constructors.
What you can do is to specify initializers. In this case (constructor initializer list) you are specifying initializers for subobjects of some larger object. The order in which you specify these initializers does not matter: the compiler will call the constructors in a very specific order defined by the language specification, regardless of the order in which you specify the initializers. The base class constructors are always called first (in the order in which the base classes are listed in class definition), then the constructors of member subobjects are called (again, in the order in which these members are listed in the class definition).
(There are some peculiarities in this rule when it comes to virtual base classes, but I decided not to include them here.)
As for the bad behaviors... Of course there is a potential for "bad behaviors" here. If you assume that the order of initialization depends on the order you used in the constructor initializer list, you will most likely eventually run into an unpleasant surprise, when you discover that the compiler completely ignores that order and uses its own order (the order of declaration) instead. For example, the author of this code
might expect
a
to be initialized first, andb
to receive the initial value of5
froma
, but in reality this won't happen sinceb
is initialized beforea
.顺序是明确定义的。它不取决于您在初始化时如何指定它们。
首先调用基类构造函数
B
,然后按照声明顺序调用成员变量 (d1
&d2
)。解释@Andrey T 的回答中的评论。
标准明确定义了调用基类构造函数的顺序,如下所示:
虚拟基类
MyClass3
优先于基类MyClass2
。The order is well defined. It does not depend on how you specify them while initializtion.
Base class constructor
B
will be called first and then the member variables(d1
&d2
) in the order in which they are declared.To explain the comment in @Andrey T's answer.
The order of calling the Base class constructors is well defined by the standard and will be:
The virtual Base class
MyClass3
is given preference over Base ClassMyClass2
.事物在初始化列表中出现的顺序并不重要。在您的情况下,基础对象将始终首先初始化,然后按顺序初始化 d1 和 d2。初始化是按照派生的顺序以及成员在类定义中出现的顺序执行的。
话虽如此,通常认为按照初始化顺序编写初始化列表是一种很好的风格,如果不这样做,一些编译器会发出警告。
The order things appear in the initialisation list is not significant. In your case, the base object will always be initialised first, followed by d1 and d2, in that order. Initialisation is performed in order of derivation and in order members appear in the class definition.
Having said that, it is normally considered good style to write the initialisation list in the order of initialisation, and some compilers will issue a warning if you don't do this.