порядок вызова конструктора с композицией

У меня класс А и класс Б. Класс C является производным от класса B и имеет объект класса A в качестве композиции. http://ideone.com/JGT48M

#include "iostream"
using namespace std;

class A {
  int i;
public:
  A(int ii) : i(ii) {
      cout << "\n Constructor of A is called \n";

  }
  ~A() {
      cout << "\n destructor  of A is called \n";
  }
  void f() const {}
};

class B {
  int i;
public:
  B(int ii) : i(ii) {
      cout << "\n Constructor of B is called \n";
  }
  ~B() {
      cout << "\n destructor  of B is called \n";
  }
  void f() const {}
};

class C : public B {
  A a;
public:
  C(int ii) : a(ii), B(ii) {
      cout << "\n Constructor of C is called \n";
  }
  ~C() {
  cout << "\n destructor  of C is called \n";
  } // Calls ~A() and ~B()
  void f() const {  // Redefinition
    a.f();
    B::f();
  }
};

int main() {
  C c(47);
} ///:~

Я читал, что конструкторы вызываются на основе того, как они вызываются в конструкторе моего производного класса. Я имею в виду, что пусть будет класс с именем REF, производный от REF_BASE1 и REF_BASE2, тогда

 REF (int ii) : REF_BASE2(ii), REF_BASE1 (ii) {

будет означать, что сначала будет вызываться REF_BASE2, затем REF_BASE1, а затем вызывается конструктор REF. и если мы определили это как

REF (int ii) : REF_BASE1(ii), REF_BASE2 (ii) {

будет означать, что сначала будет вызываться REF_BASE1, затем REF_BASE2, а затем вызывается конструктор REF.

Однако в моей программе выше я явно «неправильно» заявил, что с помощью внутренней переменной композиции A сначала инициализируется a, а затем B должен быть инициализирован, но компилятор делает это правильно, но не сообщает мне о моей ошибке.

вывод вышеуказанной программы независимо от порядка, который я указываю в списке инициализации конструктора производного класса,

Constructor of B is called 

 Constructor of A is called 

 Constructor of C is called 

 destructor  of C is called 

 destructor  of A is called 

 destructor  of B is called 

Мой вопрос: 1) почему компилятор не жалуется? или я прав? 2) строго ли не соблюдается порядок в производном конструкторе?


person MAG    schedule 01.06.2013    source источник
comment
Компилятор выдает мне предупреждение: поле 'a' будет инициализировано после базы 'B' [-Wreorder]   -  person awesoon    schedule 01.06.2013


Ответы (1)


Начну со второго вопроса:

2) строго ли не соблюдается порядок в производном конструкторе?

Порядок не тот, который появляется в списке инициализации вашего конструктора, а тот, в котором базовые классы появляются в вашем определении класса.

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

struct A : B, C
{
    // ...
};

Тогда конструктор B будет вызываться перед конструктором C, независимо от того, какой порядок вы укажете в списке инициализации конструктора A.

Параграф 12.6.2/10 стандарта C++11 определяет:

В конструкторе без делегирования инициализация выполняется в следующем порядке:

— Во-первых, и только для конструктора самого производного класса (1.8), виртуальные базовые классы инициализируются в том порядке, в котором они появляются при обходе в глубину слева направо ориентированного ациклического графа базовых классов, где «слева -to-right» — это порядок появления базовых классов в списке базовых спецификаторов производных классов.

— Затем прямые базовые классы инициализируются в порядке объявления, как они появляются в списке базовых спецификаторов (независимо от порядка мем-инициализаторов).

— Затем нестатические данные-члены инициализируются в том порядке, в котором они были объявлены в определении класса (опять же, независимо от порядка мем-инициализаторов).

— Наконец, выполняется составной оператор тела конструктора.

Теперь первый вопрос:

1) почему компилятор не жалуется?

Компилятор может предупредить вас, что порядок инициализации в списке инициализаторов конструктора отличается от порядка в списке базового класса (GCC делает это с -Wall), но не обязан. В конце концов, только последнее имеет значение.

person Andy Prowl    schedule 01.06.2013