Порядок вызова конструктора базового класса из списка инициализации производного класса - PullRequest
10 голосов
/ 06 июня 2011
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
};

Выше просто псевдокод. На самом деле я хотел знать, имеет ли значение порядок вызова базового конструктора? Есть ли плохое поведение (особенно угловые случаи ), вызванное каким-либо из случаев? Мой вопрос касается более технического аспекта и , а не о стилях кодирования.

Ответы [ 3 ]

16 голосов
/ 06 июня 2011

Порядок, который вы указываете в своем вопросе, не является "порядком вызова базового конструктора".На самом деле, вы не можете вызвать конструктор.Конструкторы не могут быть вызваны пользователем.Только компилятор может вызывать конструкторы.

Что вы можете сделать, это указать инициализаторы .В этом случае (список инициализатора конструктора) вы указываете инициализаторы для подобъектов более крупного объекта.Порядок, в котором вы указываете эти инициализаторы, не имеет значения: компилятор будет вызывать конструкторы в очень специфическом порядке, определенном спецификацией языка, независимо от порядка, в котором вы указываете инициализаторы.Сначала всегда вызываются конструкторы базового класса (в порядке, в котором базовые классы перечислены в определении класса), затем вызываются конструкторы подобъектов-членов (опять же, в порядке, в котором эти члены перечислены в определении класса).

(В этом правиле есть некоторые особенности, когда речь идет о виртуальных базовых классах, но я решил не включать их здесь.)

Что касается плохого поведения ... Конечно, естьпотенциал для "плохого поведения" здесь.Если вы предполагаете, что порядок инициализации зависит от порядка, который вы использовали в списке инициализатора конструктора, вы, скорее всего, в конечном итоге столкнетесь с неприятным сюрпризом, когда обнаружите, что компилятор полностью игнорирует этот порядок и использует свой собственный порядок (порядокдекларация) вместо.Например, автор этого кода

struct S {
  int b, a;
  S() : a(5), b(a) {}
};

может ожидать, что a будет инициализирован первым, а b получит начальное значение 5 от a, но в действительности это выигралоне происходит, поскольку b инициализируется до a.

6 голосов
/ 06 июня 2011

Порядок четко определен.Это не зависит от того, как вы их указали при инициализации.
Сначала будет вызван конструктор базового класса B, а затем переменные-члены (d1 & d2) в порядке их объявления.

Чтобы объяснить комментарий в ответе @Andrey T.

class MyClass1: public MyClass2, public virtual MyClass3
{


};

Порядок вызова конструкторов базового класса хорошо определен стандартом и будет:

MyClass3  
MyClass2
MyClass1

Виртуальному базовому классу MyClass3 отдается предпочтение перед базовым классом MyClass2.

3 голосов
/ 06 июня 2011

Порядок вещей в списке инициализации не имеет значения. В вашем случае базовый объект всегда будет инициализирован первым, а затем d1 и d2 в этом порядке. Инициализация выполняется в порядке деривации и в порядке появления членов в определении класса.

Сказав это, обычно считается хорошим стилем писать список инициализации в порядке инициализации, и некоторые компиляторы выдают предупреждение, если вы этого не сделаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...