- •45. Вызовы конструкторов в процессе работы программы.
- •48. Деструкторы.
- •49. Поля данных. Нестатические и статические поля – особенности их создания и инициализации. Правила обращения к полям. Константные поля.
- •50. Методы. Основные правила работы с методами. Константные методы. Статические методы.
- •51. Указатель this.
- •52. Дружественные функции и классы.
- •53. Перегрузка операций – общие положения.
- •54. Перегрузка операции присваивания. Особенности работы с ресурсоемкими объектами.
- •55. Перегрузка унарных операций.
- •56. Перегрузка бинарных операций.
- •57. Особенности определения классов с ключами struct и union.
- •58. Включение классов.
- •59. Наследование классов – общие положения.
- •Класс а
- •61. Общие особенности механизма простого наследования классов.
- •62. Множественное наследование.
- •63. Перечень специальных методов класса. Особенности определения конструкторов и деструкторов в производных классах.
- •64. Особенности определения и применения функций-операций «присваивание» в производных классах.
- •65. Особенности перегрузки операций в производных классах.
- •66. Общая характеристика виртуальных функций.
62. Множественное наследование.
Наследование является множественным, если при производном классе указывается 2 или более базовых классов. Синтаксис определим примером:
class x1 {…};
class x2 {…};
class x3 {…};
class y: public x1, protected x2, x3 {…}; // здесь класс y наследует элементы 3-х классов, каждый из 3-х базовых классов должен быть указан со своим спецификатором, может быть неявно. Схема этой иерархии классов такова:
x1
x2
x3
y
Рис. 4.2 «Пример множественного наследования»
Один и тот же класс может быть непрямым базовым классом у данного производного класса
Пример:
class x {long double ax};
class y1: public x {double ay1};
class y2: public x {int ay2};
class z: public y1, public y2 { };
Схема иерархии:
x
x
z
y1
y2
Рис. 4.3 «пример множественного наследования с многократным использованием класса x в качестве непрямого базового»
Соответствующие объемы этих классов будут такими:
size (X) = 10 байт (long double)
size (Y1) = 18байт (long double + double)
size (Y2) = 14байт (long double + int)
size (Z) = 32байта (long double + long double + double + int)
таким образом ax класса X дважды будет повторяться Z, так как имя поля в обеих ветвях наследования наследования одинаково, то при обращении к конкретному полю необходимо указывать по какой ветви прошло наследование
Z:: Y1:: X:: ax // наследование через класс Y1
Z:: Y2:: X:: ax // наследование через класс Y2
Если по запланированной логике построения иерархии классов повторение поля ax является лишним, то необходимо объявить, что класс X наследуется как виртуальный, то есть объявление должно иметь вид:
class Y1: virtual public X {double ay1}
class Y2: virtual public X {double ay2}
Объявленные при этом X и Z не меняются. На схемах такое наследование изображается в виде ромбовитых диаграмм:
Y1
X
Z
Y2
Рис. 4.4 «Пример виртуального наследования класса X»
Виртуальное наследование обеспечивается благодаря тому, что компилятор добавляет по еще одному полю Y1, Y2 – это указывает на виртуальный базовый класс. Зная этот класс компилятор исключает дублирование полей непрямого базового класса, поэтому размеры классов будут такими:
size (X) = 10байт (long double)
size (Y1) = 22байта (long double + double + X*) // добавляется указатель X
size (Y2) = 18байт (long double + int + X*)
size (Z) = 30байт (long double + double + int + X* + X*) // лишнее поле long double исчезло, но появилось два указателя поля, унаследованные от прямых базовых классов Y1 и Y2
Таким образом, в общем случае объект производного класса определяется с виртуальным наследованием, включая в себя базовый класс, указатель на объект базового класса. Если в свою очередь 2 или более производных класса Y1 и Y2 становятся базовыми для 3-го уровня Z, то поля непрямого базового класса не дублируются, но указывают наследника от всех прямых базовых классов Y1 и Y2.
Непрямой базовый класс может быт включен в иерархию наследования одновременно и как обычный базовый класс, и как виртуальный базовый класс.
class X {long double ax};
class Y1: virtual public X {double ay1};
class Y2: virtual public X {double ay2};
class Y3: public X {int ay3};
class Z: public Y1, public Y2, public Y3 { };
Схема иерархии такова:
X
Y1
Y2
Z
Y3
X
Рис. 4.5 «Пример смешанного наследования класса X»
Размеры объектов таковы:
size (Y1) = 22байта (long double + double + X*)
size (Y2) = 18байт (long double + int + X*)
size (Y3) = 14байт (long double + int)
size (Z) = 44байта (long double + double + int + X* + X* + long double + int)
Особое определение и применение специальных методов в производном классе:
В С++ относ. спец. методы:
конструктор умолчания
конструктор копирования
деструктор
функция операция присваивания
общим для них является тот факт, что если программист явно не определит эти методы, то компилятор создаст их автоматически, другая их особенность заключается в том, сто они не наследуются, однако, при этом аналогичный метод базового класса вызывается по специальным правилам при вызове метода производного класса.