Порядок создания виртуальных базовых классов

У меня есть следующая проблема:

struct A1 {
A1() { std::cout << "A1, "; }
};

struct A2 {
A2() { std::cout << "A2, "; }
};

struct AA1 : virtual A1,  A2 {
AA1() { std::cout << "AA1, "; }
};

struct AA2 : A1, virtual A2 {
AA2(){ std::cout << "AA2, "; }
};

struct B : AA1, virtual AA2 {
B() { std::cout << "B "; }
};

int main() {
B b;
}

Когда вы запускаете этот код, ответ:

A1 A2 A1 AA2 A2 AA1 B

Я хочу понять, где первый A1 создано.

Я знаю правило, что виртуальные классы вызываются раньше, чем не виртуальные классы, но первый A1 — это проблема, которая беспокоит меня.

4

Решение

Первый A1 результаты инициализации (виртуальной) базы (не виртуальной) базы AA1 из B,

Все виртуальные базы B инициализируются в первую очередь, и они, по порядку, A1, A2 а также AA2, (Инициализация AA2 результаты в выводе A1 AA2.) Затем приходят прямые основания, из которых есть только одна, AA1 (чья инициализация печатает A2 AA1) и наконец сам класс, печать B, Сначала идут все виртуальные базы, а затем только оставшиеся не виртуальные.

2

Другие решения

B имеет три виртуальных базовых класса: A1, A2 а также AA2и, в соответствии с их порядком появления, он будет инициализировать их в этом порядке.

Первый A1 а также A2 вы видите инициализацию виртуальной базы A1 а также A2, но последняя виртуальная база AA2 имеет не виртуальную базу A1, так что перед построением AA2вам нужно будет построить другой A1вот почему у вас есть другой A1 до AA2,

Вы можете визуализировать это, запустив следующий фрагмент:

#include <iostream>

struct A1 {
A1(const char *s) { std::cout << "A1(" << s << ")\n"; }
};

struct A2 {
A2(const char *s) { std::cout << "A2(" << s << ")\n"; }
};

struct AA1 : virtual A1,  A2 {
AA1(const char *s) : A1("AA1"), A2("AA1") { std::cout << "AA1(" << s << ")\n"; }
};

struct AA2 : A1, virtual A2 {
AA2(const char *s) : A1("AA2"), A2("AA2") { std::cout << "AA2(" << s << ")\n"; }
};

struct B : AA1, virtual AA2 {
B() : A1("B"), A2("B"), AA1("B"), AA2("B") { std::cout << "B()\n"; }
};

int main() {
B b;
}

Это выведет:

A1(B)
A2(B)
A1(AA2)
AA2(B)
A2(AA1)
AA1(B)
B()

Вы также можете заметить, что этот код предупреждает вас, потому что:

  • я кладу A1 до A2 в AA2конструктор, но A2 будет инициализирован раньше A1 (потому что это виртуальная база и A1 не является).
  • я кладу AA1 до AA2 в Bконструктор, но AA2 будет инициализирован первым (по той же причине).
2

По вопросам рекламы [email protected]