13 Derived classes [class.derived]

13.1 Multiple base classes [class.mi]

Класс может быть производным от любого количества базовых классов. [ Note: Использование более одного прямого базового класса часто называется множественным наследованием. ] [end noteExample:

class A { /* ... */ };
class B { /* ... */ };
class C { /* ... */ };
class D : public A, public B, public C { /* ... */ };

end example]

[ Note: Порядок вывода не имеет значения, за исключением случаев, указанных в семантике инициализации с помощью конструктора ([class.base.init]) cleanup, и разметки хранилища ([class.mem], [class.access.spec]). ]end note

Класс не должен указываться как прямой базовый класс производного класса более одного раза. [ Note: Класс может быть косвенным базовым классом более одного раза и может быть прямым и косвенным базовым классом. Есть ограниченное количество вещей, которые можно сделать с таким классом. На нестатические элементы данных и функции-члены прямого базового класса нельзя ссылаться в области производного класса. Однако на статические члены, перечисления и типы можно однозначно ссылаться. ] [end noteExample:

class X { /* ... */ };
class Y : public X, public X { /* ... */ };             // ill-formed
class L { public: int next;  /* ... */ };
class A : public L { /* ... */ };
class B : public L { /* ... */ };
class C : public A, public B { void f(); /* ... */ };   // well-formed
class D : public A, public L { void f(); /* ... */ };   // well-formed

end example]

Спецификатор базового класса, не содержащий ключевого слова, virtual задает non-virtual base class. Спецификатор базового класса, содержащий ключевое слово, virtual задает virtual base class. Для каждого отдельного вхождения невиртуального базового класса в решетку классов самого производного класса most derived object должен содержать соответствующий отдельный подобъект базового класса этого типа. Для каждого отдельного базового класса, который указан как виртуальный, наиболее производный объект должен содержать единственный подобъект базового класса этого типа.

[ Note: Для объекта типа класса Cкаждое отдельное вхождение (не виртуального) базового класса L в решетку классов C однозначно соответствует отдельному L подобъекту внутри объекта типа C. Учитывая класс, C определенный выше, объект класса C будет иметь два подобъекта класса, L как показано на рисунке [fig:nonvirt].

nonvirt L1 L1 L L2 L2 L A A A A->L1 A->L1 B B B B->L2 B->L2 C C C C->A C->A C->B C->B
Рисунок 3 - Невиртуальная база

В таких решетках можно использовать явную квалификацию, чтобы указать, какой подобъект имеется в виду. Тело функции C​::​f может относиться к члену next каждого L подобъекта:

void C::f() { A::next = B::next; }      // well-formed

Без квалификаторов A​::​ или B​::​ приведенноеC​::​f выше определение было бы некорректным из-за ambiguity. ]end note

[ Note: Напротив, рассмотрим случай с виртуальным базовым классом:

class V { /* ... */ };
class A : virtual public V { /* ... */ };
class B : virtual public V { /* ... */ };
class C : public A, public B { /* ... */ };
virt V V V A A A A->V A->V B B B B->V B->V C C C C->A C->A C->B C->B
Рисунок 4 - Виртуальная база

Для объекта c типа класса Cединственный подобъект типа V является общим для каждого подобъекта базового класса c , имеющего virtual базовый класс типа V. Учитывая класс, C определенный выше, объект класса C будет иметь один подобъект класса V, как показано на рисунке [fig:virt]. ]end note

[ Note: Класс может иметь как виртуальные, так и невиртуальные базовые классы данного типа.

class B { /* ... */ };
class X : virtual public B { /* ... */ };
class Y : virtual public B { /* ... */ };
class Z : public B { /* ... */ };
class AA : public X, public Y, public Z { /* ... */ };

Для объекта класса AAвсе virtual вхождения базового класса B в решетке классов AA соответствуют одному B подобъекту в объекте типа AA, а каждое другое вхождение (не виртуального) базового класса B в решетке классов AA соответствует взаимно-однозначно. один с отдельным B подобъектом внутри объекта типа AA. Учитывая класс, AA определенный выше, у класса AA есть два подобъекта класса B: Zs B и виртуальный, B совместно используемый X и Y, как показано на рисунке [fig:virtnonvirt].

virtnonvirt B1 B1 B B2 B2 B AA AA AA X X X AA->X AA->X Y Y Y AA->Y AA->Y Z Z Z AA->Z AA->Z X->B1 X->B1 Y->B1 Y->B1 Z->B2 Z->B2
Рисунок 5 - Виртуальная и не виртуальная база

end note]