C++: гарантии порядка построения и инициализации

У меня есть некоторые сомнения относительно гарантий порядка построения и инициализации в C++. Например, следующий код имеет четыре класса X, Y, Z и W. Основная функция создает экземпляр объекта class X, который содержит объект class Y и является производным от class Z, поэтому будут вызваны оба конструктора. Кроме того, параметр const char*, переданный конструктору X, будет неявно преобразован в объект class W, поэтому также должен быть вызван конструктор W.

Какие гарантии дает стандарт С++ в отношении порядка вызовов конструкторов копирования? Или, что то же самое, что этой программе разрешено печатать?

#include <iostream>

class Z {
   public:
   Z() { std::cout << "Z" << std::endl; }
};

class Y {
   public:
   Y() { std::cout << "Y" << std::endl; }
};

class W {
   public:
   W(const char*) { std::cout << "W" << std::endl; }
};

class X : public Z {
   public:
   X(const W&) { std::cout << "X" << std::endl; }
   private:
   Y y;
};

int main(int, char*[]) {
   X x("x");
   return 0;
}

редактировать: это правильно?

   W      |
 /   \    |
Z     Y   |
 \   /    |
   X      V

person Giovanni Funchal    schedule 25.03.2010    source источник
comment
Порядок будет W, Z, Y, X, но я не уверен в конкретных правилах.   -  person Charles Beattie    schedule 25.03.2010
comment
Какая связь между Y и W?   -  person curiousguy    schedule 26.08.2015


Ответы (5)


Во всех классах гарантируется порядок построения: базовые классы, указанные слева направо, за которыми следуют переменные-члены в порядке, объявленном в определении класса. Тело конструктора класса выполняется после того, как все его базовые элементы и конструкции членов завершены.

В вашем примере X является производным от Z и содержит Y, поэтому сначала создается базовый объект Z, затем член Y y, затем построение X завершается выполнением тела конструктора X.

Временный W необходим для передачи конструктору X, поэтому он создается до начала построения x и будет уничтожен после завершения инициализации x.

Итак, программа должна вывести:

W
Z
Y
X
person CB Bailey    schedule 25.03.2010

1) В первую очередь нужно вычислить аргументы.

2) Затем строятся базовые классы.

3) Затем члены строятся в порядке появления в объявлении класса.

4) Затем вызывается конструктор X

person Alexey Malistov    schedule 25.03.2010
comment
просто добавить... базовые классы также строятся в порядке слева направо, в котором они появляются при наследовании - person Yogesh Arora; 25.03.2010

  1. Объект W будет создан до вызова конструктора X.
  2. Z, как базовый класс X, будет инициализирован перед членами X.
  3. Y будет инициализирован во время инициализации члена
  4. Конструктор X будет запущен.
person jwismar    schedule 25.03.2010

Чтобы расширить ответ Чарльза Бейли, правила меняются, когда ваши базовые классы наследуются виртуально. Я всегда забываю, каков порядок, на сайте IBM говорится, что сначала инициализируются виртуальные базы, но я просто никогда не сталкивался со случаем, когда на самом деле это больше, чем просто мелочи.

person Edward Strange    schedule 25.03.2010

Если обобщить, то это правила:

  1. Аргументы, взятые справа налево
    а. Самый правый
    b. 2-й справа
  2. Базовый класс
  3. Виртуальная база
  4. Базовые классы слева направо
  5. Члены в порядке объявления в классе
  6. Конструктор вызываемого класса
person Amit Singh    schedule 26.08.2015