从派生类初始化列表调用基类构造函数的顺序

iam*_*ind 10 c++ constructor base-class initialization-list

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
};
Run Code Online (Sandbox Code Playgroud)

以上只是伪代码.实际上我想知道调用基础构造函数顺序是否重要? 是否有任何不良行为(特别是拐角案件)由任何案件引起?我的问题是更多的技术方面,而不是编码风格.

AnT*_*AnT 16

您在问题中引用的顺序不是"调用基础构造函数的顺序".实际上,你不能调用构造函数.构造函数不能由用户调用.只有编译器可以调用构造函数.

你可以做的是指定初始化器.在这种情况下(构造函数初始化列表),您要为某个较大对象的子对象指定初始值设定项.指定这些初始值设定项的顺序无关紧要:编译器将按照语言规范定义的非常特定的顺序调用构造函数,而不管指定初始值设定项的顺序如何.始终首先调用基类构造函数(按照类定义中列出基类的顺序),然​​后调用成员子对象的构造函数(同样,按照类定义中列出这些成员的顺序).

(当涉及到虚拟基类时,这条规则有一些特点,但我决定不在这里包含它们.)

至于不良行为......当然,这里存在潜在的"不良行为".如果你假设初始化的顺序取决于你在构造函数初始化程序列表中使用的顺序,当你发现编译器完全忽略该顺序并使用它自己的顺序时,你很可能最终会遇到令人不快的意外(顺序)声明)而不是.例如,此代码的作者

struct S {
  int b, a;
  S() : a(5), b(a) {}
};
Run Code Online (Sandbox Code Playgroud)

可能期望a首先初始化,并b接收5from 的初始值a,但实际上这不会发生,因为b之前已初始化a.

  • 也许值得一提的是,虚拟Base类按照Base类的初始化顺序给出了优先级. (3认同)
  • “用户无法调用构造函数。只有编译器可以调用构造函数。” 构造函数不是通过放置 new 手动调用的吗?或者这被认为是“运行”构造函数? (3认同)
  • @Als:...除非您构建派生最多的对象,否则将忽略虚拟基类初始值设定项.我不想让这些问题超出我的答案. (2认同)

Alo*_*ave 6

订单定义明确.它不依赖于您在初始化时如何指定它们.首先调用
基类构造函数B,然后按成员变量(d1&d2)的顺序调用它们.

解释@Andrey T答案中的评论.

class MyClass1: public MyClass2, public virtual MyClass3
{


};
Run Code Online (Sandbox Code Playgroud)

调用Base类构造函数的顺序由标准很好地定义,并且将是:

MyClass3  
MyClass2
MyClass1
Run Code Online (Sandbox Code Playgroud)

虚基类MyClass3优先于基类MyClass2.