- •Введение. Принципы объектно-ориентированного программирования
- •Глава 1. Классы и объекты
- •1.1. Операция разрешения области видимости ::
- •1.2. Перечислимый тип
- •1.3. Модификатор const
- •1.4. Новый тип данных – ссылка &
- •Inline определение_функции
- •2. Определение класса. Сокрытие информации.
- •3. Объект.
- •4. Конструкторы и деструкторы
- •4.1.Назначение конструктора
- •4.2. Конструктор копирования
- •X::X(X&); // где X – имя класса
- •4.3. Деструктор
- •5. Неявный указатель this
- •6. Перегрузка операций
- •7. Примеры перегрузки некоторых операций
- •7.1. Перегрузка операции [ ]
- •7.2. Перегрузка операции ()
- •7.6. Перегрузка операции (тип)
- •8. Дружественность
- •Istream
- •10. Массивы объектов.
- •11. Функции- и классы-шаблоны
- •11.1 Функции-шаблоны (родовые функции)
- •11.2 Классы-шаблоны
- •12. Член-данные класса – объекты другого класса: агрегированные классы.
- •Глава 2. Наследование. Полиморфизм
- •1. Базовый и порожденный классы
- •2. Конструкторы порожденного класса
- •3. Стандартные преобразования при наследовании
- •4. Множественное наследование. Виртуальный базовый класс
- •4.1. Прямые базовые классы
- •4.2. Виртуальный базовый класс
- •5. Полиморфизм, раннее и позднее связывание, виртуальные функции
- •5.1 Раннее (статическое) и позднее (динамическое) связывание
- •5.2. Определение виртуальной функции
- •5.3. Чистая виртуальная функция и абстрактный класс
- •5.4. Правила определения виртуальных функций
- •5.5. Механизм позднего связывания
- •6. Библиотека fstream – работа с файлами
- •Глава 3. Библиотека стандартных шаблонов (бсш). Контейнеры
- •1. Контейнер. Структура бсш.
- •2. Контейнер Vector – динамический массив
- •Контейнер list – список
- •4. Контейнер Set – множество
- •Содержание
- •Глава 1. Классы и объекты
- •Глава 2. Наследование. Полиморфизм
- •Глава 3. Библиотека стандартных шаблонов (бсш). Контейнеры
2. Конструкторы порожденного класса
Если объявляется объект порожденного класса, то за инициализацию базовой части объектов должен отвечать конструктор порожденного класса. Поэтому конструктор класса B имеет специальную форму (на примере наших классов A и B):
список инициализации
B:: B(int a, int b, int c) : A(a, b, c)
{ d3 = d4 = b;}
В список инициализации может быть включена инициализация член-данных порожденного класса.
Например,
B:: B(int a, int b, int c): A(a, b, c), d3(b), d4(b) { } (1)
Заметим, что для нашего примера инициализация может выглядеть и другими способами:
B:: B(int a, int b, int c, int d, int r): A(a, b, c), d3(d), d4(r) { } (2)
Пример использования конструкторов:
void main( )
{A x, y(3, 6, 7); // конструкторы без аргументов и с аргументами класса A
B z(1, 2, 3, 4, 5); // конструктор (2): 1, 2, 3 инициализируют базовую часть объекта z (d1, d2, d3),
// а 4, 5 – порожденную (d3, d4)
}
Если в базовом классе задан конструктор по умолчанию, то в списке инициализации конструктора порожденного класса он может отсутствовать. То есть конструктор класса B может иметь вид:
B:: B(int a, int b): A( ) {d3 = a; d4 = b;}
или
B:: B(int a, int b) {d3 = a; d4 = b;}
Однако и в первом и во втором случае конструктор по умолчанию класса A работать будет. При инициализации объектов порожденного класса сначала работают конструкторы базового, а затем порожденных классов и так по всей иерархии порождения. Этот факт позволяет при инициализации член-данных порожденного класса использовать уже проинициализированные член-данные базового класса. То есть конструктор класса B может быть задан таким необычным образом:
B:: B(int a, int b, int c): A(a, b, b) // A:: d1 = a; A:: d2 = b; A:: d3 = b
{d3 = d2 * A:: d3; d4 = c;}
Деструкторы, наоборот, сначала разрушают член-данные порожденного класса, затем базового.
3. Стандартные преобразования при наследовании
Пусть заданы объекты порожденного класса и базового
A x ; B y(1, 2, 3, 4, 5); // конструктор (2)
Что будет верным:
x = y;
или
y = x; ?
Ответ: x = y;
При наследовании действуют по умолчанию такие правила преобразования:
объект порожденного класса преобразуется к объекту базового (путем отбрасывания порожденных член-данных). В обратную сторону преобразование не определено (и может быть задано только пользователем, как правило, конструктором вида B(A&) ).
ссылка или указатель порожденного класса преобразуются в ссылку или указатель на базовый класс.
Преобразование указателя на объект базового класса к указателю на объект порожденного может быть выполнено явно по операции (тип), где в качестве типа задается указатель на порожденный класс.
Итак,
void main( )
{A x, *pA; // Для x работает конструктор по умолчанию
B y(1, 2, 3, 4, 5), *pB; // Для y работает конструктор (2)
x = y; // Верно: x.d1 = y.d1 = 1; x.d2 = y.d2 = 2; x.d3 = y.A:: d3 = 3;
y = x; // Неверно: что записать в y.d3, y.d4 из x?
// как из маленького пальто нельзя сшить большое, а наоборот – можно (см. рисунок)
pA = &y; // верно: преобразование B* –> A* определено по умолчанию
pA –> Print( ); //функция A::Print() выведет базовую часть объекта y
pB = &x; // неверно, преобразование A* –> B* неопределенно по умолчанию
pB = (A *)pA; // операция явного преобразования A* –> B*
}
Замечание. Если в классах A и B определяются конструкторы копирования
A(A &) и B(B &),
то последний имеет вид
B:: B(B &b1): A(b1) {...},
в котором в списке инициализации базовая часть объекта b1 передается конструктору копироваия класса A. При этом используется стандартное преобразование объектов порожденного класса к базовому.
