Endangered(Endangered::critical),
sleeping_flag(false) { }
Порядок создания объекта с виртуальным базовым классом немного отличается от обычного: сначала инициализируется часть виртуального базового класса с использованием инициализаторов, предоставленных в конструкторе для наиболее производного класса. Как только создана часть виртуального базового класса, создаются части прямых базовых классов в порядке их расположения в списке наследования.
Например, объект класса Panda
создается так.
• Сначала создается часть виртуального базового класса ZooAnimal
. При этом используются инициализаторы из списка инициализации конструктора класса Panda
.
• Затем создается часть Bear
.
• Затем создается часть Raccoon
.
• Следующей создается часть прямого базового класса Endangered
.
• Наконец создается часть Panda
.
Если конструктор класса Panda
не инициализирует явно часть базового класса ZooAnimal
, будет использован стандартный конструктор класса ZooAnimal
. Если у класса ZooAnimal
нет стандартного конструктора, произойдет ошибка.
У класса может быть несколько виртуальных базовых классов. В этом случае части виртуальных классов создаются в порядке их расположения в списке наследования. Например, в следующей иерархии наследования у класса TeddyBear
(МедвежонокТедди) есть два виртуальных базовых класса: прямой виртуальный базовый класс ToyAnimal
(ИгрушечноеЖивотное) и косвенный базовый класс ZooAnimal
, от которого происходит класс Bear
:
class Character { /* ... */ };
class BookCharacter : public Character { /* ... */ };
class ToyAnimal { /* ... */ };
class TeddyBear : public BookCharacter,
public Bear, public virtual ToyAnimal
{ / * ... * / };
Чтобы выявить наличие виртуальных базовых классов, прямые базовые классы просматриваются в порядке объявления. Если это так, то сначала создаются части виртуальных базовых классов, затем выполняются конструкторы обычных, не виртуальных базовых классов в порядке их объявления. Таким образом, чтобы создать объект класса TeddyBear
, конструкторы его частей вызываются в следующем порядке:
ZooAnimal(); //
ToyAnimal(); //
Character(); //
// базового класса
BookCharacter(); //
Bear(); //
TeddyBear(); //
Тот же порядок создания используется в синтезируемом конструкторе копий и конструкторах перемещения, в синтезируемых операторах присвоения члены присваиваются в том же порядке. Вызов деструкторов базовых классов осуществляется в порядке, обратном порядку вызова конструкторов. Часть TeddyBear
будет удалена сначала, а часть ZooAnimal
— последней.
Упражнение 18.29. Имеется следующая иерархия классов:
class Class { ... };
class Base : public Class { ... };
class D1 : virtual public Base { ... };
class D2 : virtual public Base { ... };
class MI : public D1, public D2 { ... };
class Final : public MI, public Class { ... };
(a) Каков порядок вызова конструкторов и деструкторов объектов класса Final
?
(b) Сколько внутренних объектов класса Base
находится в объекте класса Final
? А сколько внутренних объектов класса Class
?
(c) Какие из следующих случаев присвоения приведут к ошибке во время компиляции?
Base *pb; Class *pc; MI *pmi; D2 *pd2;
(a) pb = new Class; (b) pc = new Final;
(c) pmi = pb; (d) pd2 = pmi;