Вызывается ли несколько наследуемых конструкторов несколько раз? - PullRequest
19 голосов
/ 13 сентября 2011

Вызывается ли несколько наследуемых конструкторов несколько раз?И в каком порядке называются конструкторы?Зависит ли это от порядка в списке наследования?

Вот пример (это только для прояснения ситуации, без примера из реальной жизни).* конструктор вызывается дважды?И в каком порядке называются конструкторы?База первая?Или DerivedBaseOne() или DerivedBaseTwo() сначала?

Ответы [ 3 ]

19 голосов
/ 13 сентября 2011

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

Base()  
DerivedBaseTwo()  
Base()
DerivedBaseOne()  
Derived()

Порядок действительно хорошо определен и зависит от порядка, в котором вы упоминаете деривацию для базовых классов, и порядка, в которомВы объявляете участников в классе для участников.(См. Ссылку на стандарт C ++ ниже.)

Дважды вызывается конструктор Base ()?
ДА

Конструктор класса Base() вызывается здесь дважды, потому что два класса DerivedBaseTwo() и DerivedBaseOne() являются производными от него, поэтому конструктор базового класса вызывается один раз для каждого из них.Ваш Derived класс имеет два отдельных Base подобъекта по нескольким путям (от одного до DerivedBaseOne(), а другой через DerivedBaseTwo()).

Иерархия классов с множественным наследованием необычна и приводит кк проблеме, называемой Проблема наследования в форме ромба .Чтобы избежать этой проблемы, C ++ вводит понятие Виртуальный базовый класс .


Ссылка:

C ++ 03 Standard: 12.6.2 / 5, Инициализация баз и членов

Инициализация должна выполняться в следующем порядке:

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

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

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

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

14 голосов
/ 13 сентября 2011

Как вы пишете, Derived имеет два различных подобъекта типа Base, и каждый получает свой собственный конструктор, вызываемый из соответствующего DerivedBaseXXX конструктора, к которому он относится. Порядок звонков соответствует порядку объявления.

В отличие от вас, вы объявляете DerivedBaseXXX : virtual public Base, тогда есть только один Base подобъект, и его конструктор вызывается из самого производного объекта, то есть из объекта Derived.

(Чтобы объяснить более подробно: класс (возможно, наследуемый по одиночке) создается сначала 1) вызовом конструктора базового класса, затем 2) вызовом конструкторов всех объектов-членов в порядке их объявления и, наконец, 3) выполнение тела функции конструктора. Это применяется рекурсивно, и для множественного наследования вы просто заменяете (1), вызывая все конструкторы базового класса в порядке, в котором было объявлено наследование. Только виртуальное наследование добавляет здесь дополнительный уровень сложности.)

3 голосов
/ 13 сентября 2011

Ответ на этот вопрос: http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.14

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

Поскольку ваше объявление множественного наследования сначала перечисляет DerivedBaseTwo, его порядок построения будет выполняться до DerivedBaseOne.

Итак, в вашем классе Derived сначала создается DerivedBaseTwo и его цепочка, то есть:

1 - Base, затем DerivedBaseTwo

А затем DerivedBaseOne и его цепочка:

2 - Base, затем DerivedBaseOne

А потом:

3 - Derived создается после всего остального.

Кроме того, при множественном наследовании следует помнить о проблеме наследования алмазов

...