Порядок вызова конструкторов и деструкторов
Виртуальные базовые классы всегда конструируются перед невиртуальными, вне зависимости от их расположения в иерархии наследования. Например, в приведенной иерархии у класса TeddyBear (плюшевый мишка) есть два виртуальных базовых: непосредственный– ToyAnimal (игрушечное животное) и экземпляр ZooAnimal, от которого унаследован класс Bear:
class Character { ... }; // персонаж
class BookCharacter : public Character { ... };
// литературный персонаж
class ToyAnimal { ... }; // игрушка
class TeddyBear : public BookCharacter,
public Bear, public virtual ToyAnimal
{ ... };
Эта иерархия изображена на рис. 18.5, где виртуальное наследование показано пунктирной стрелкой, а невиртуальное – сплошной.
Character ZooAnimal ToyAnimal
BookCharacter Bear
TeddyBear
¾¾> невиртуальное наследование
- - - -> виртуальноe наследование
Рис. 18.5. Иерархия виртуального наследования класса TeddyBear
Непосредственные базовые классы просматриваются в порядке их объявления при поиске среди них виртуальных. В нашем примере сначала анализируется поддерево наследования BookCharacter, затем Bear и наконец ToyAnimal. Каждое поддерево обходится в глубину, т.е. поиск начинается с корневого класса и продвигается вниз. Так, для поддерева BookCharacter сначала просматривается Character, а затем BookCharacter. Для поддерева Bear – ZooAnimal, а потом Bear.
При описанном алгоритме поиска порядок вызова конструкторов виртуальных базовых классов для TeddyBear таков: ZooAnimal, потом ToyAnimal.
После того как вызваны конструкторы виртуальных базовых классов , настает черед конструкторов невиртуальных, которые вызываются в порядке объявления: BookCharacter, затем Bear. Перед выполнением конструктора BookCharacter вызывается конструктор его базового класса Character.
Если имеется объявление:
TeddyBear Paddington;
то последовательность вызова конструкторов базовых классов будет такой:
ZooAnimal(); // виртуальный базовый класс Bear
ToyAnimal(); // непосредственный виртуальный базовый класс
Character(); // невиртуальный базовый класс BookCharacter
BookCharacter(); // непосредственный невиртуальный базовый класс
Bear(); // непосредственный невиртуальный базовый класс
TeddyBear(); // ближайший производный класс
причем за инициализацию ZooAnimal и ToyAnimal отвечает TeddyBear – ближайший производный класс объекта Paddington.
Порядок вызова копирующих конструкторов при почленной инициализации (и копирующих операторов присваивания при почленном присваивании) такой же. Гарантируется, что деструкторы вызываются в последовательности, обратной вызову конструкторов.