- •45. Вызовы конструкторов в процессе работы программы.
- •48. Деструкторы.
- •49. Поля данных. Нестатические и статические поля – особенности их создания и инициализации. Правила обращения к полям. Константные поля.
- •50. Методы. Основные правила работы с методами. Константные методы. Статические методы.
- •51. Указатель this.
- •52. Дружественные функции и классы.
- •53. Перегрузка операций – общие положения.
- •54. Перегрузка операции присваивания. Особенности работы с ресурсоемкими объектами.
- •55. Перегрузка унарных операций.
- •56. Перегрузка бинарных операций.
- •57. Особенности определения классов с ключами struct и union.
- •58. Включение классов.
- •59. Наследование классов – общие положения.
- •Класс а
- •61. Общие особенности механизма простого наследования классов.
- •62. Множественное наследование.
- •63. Перечень специальных методов класса. Особенности определения конструкторов и деструкторов в производных классах.
- •64. Особенности определения и применения функций-операций «присваивание» в производных классах.
- •65. Особенности перегрузки операций в производных классах.
- •66. Общая характеристика виртуальных функций.
59. Наследование классов – общие положения.
Рассмотрим отношение наследования классов, но перед этим отметим важные особенности включения класса. При включении объектов класса А как полей в объектах клааса В, последнее не получит никаких особых прав на объекты класса А.
Отношение наследования позволяет выстроить иерархию класса в рамках которой определяется базовый класс, на основе базового определения производный класс наследует элементы базового и имеет право образовывать новые элементы или видоизменять элементы базового класса.
Появляется возможность создания сложного конструктора взаимосвязи классов, причем при создании очередного поколения класса нет необходимости в нем элементы предков, так как права на эти объекты потомки получают автоматически.
В С++ различают 2 вида наследования:
простое наследование – когда в произвольном указывается 1 базовый класс
множественное наследование – когда базовых классов 2 или более, и класс может наследовать элементы из нескольких ветвей предков
Более распространенным является простое наследование.
– базовый для В1 и В1
Класс а
Класс В1
Класс В2
Класс С2
Класс С3
– производный от А, базовый для С2 и С3
Класс С1
производный от В1, А производный от В2, А
производный от А, базовый для С1 производный от В2, А
Рис. 4.1
Как показывает пример рис. 4.1 производный класс может быть базовым для другого класса.
В иерархии последовательность для С1 являются базовыми А и В1, но при это В1 – прямой базовый, а А – косвенным базовым.
Определения базовых классов должны быть даны в программе раньше определений производных классов. Пользуясь правилами языка С++ программист может реализовать различные стратегии наследования.
На простом примере проиллюстрируем 2 стратегии наследования при формировании производного класса:
образовав производные классы можно расширить спектр свойств объектов класса, стратегическое движение от общего к частному.
Образовав производные классы можно сужать спектр свойств
Пример реализации 1-й строки является определение в начале класса описание точки на плоскости, где некоторые поля объектов могут содержать координаты и другие характеристические точки. Далее можно определить класс описывающий окружность, при этом базовым можно сделать «класс точка», от которого класс «окружность» унаследует указанные поля, причем в объектах класса «окружность» эти поля будут предназначены для хранения характеристики центра. Дополнительно в классе «окружность» объявляется поле для хранения радиуса окружности. Таким образом производный класс будет иметь более широкий спектр свойств, а значит будет обладать меньшей стоимостью абстракции.
Приером реализации 2-й строки является порядок построения класса: вначале определяется класс «окружность», а затем производный класс «точка», в котором в качестве базового используется класс «окружность». Причем конструктор класса «точка» обязательно инициализирует поле – радиус 0, то есть тоска – окружность нулевого радиуса.
60. Синтаксис определения производного класса. Уровни допустимости унаследованных элементов в производном классе (из п. 4.2.1 лекций выбрать часть материала, необходимую для раскрытия перечисленных вопрсов).
Синтаксис определения производного класса при простом наследовании имеет вид:
<ключ производногго класса> <имя производного класса> :
[<спецификатор базового класса>] <имя базового класса>
{<тело класса>}
ключ производного класса – это одно из служебных слов либо с class, либо struct (union не допустимо)
двоиточие обязательно
спецификатор базового класса необязателен, а если он есть, то это одно из служебных слов public, pravit или protected, если спецификатор опущен, а ключ производного класса class, то спецификатор по умолчанию = pravit, а если ключ struct, то по умолчанию pravit
Главные вопросы, которые должен решать программист разрабатывая производный класс таковы: «Что и как, то есть по каким правилам производный класс наследует от предка?», «Видоизменяет ли он какие-нибудь элементы, и если «да», то как?», «Как дополняет производный класс предка?»
Тот факт, что в данном классе элемент попадает под действие конкретного спецификатора доступа, причем не важно объявлен спецификатор явно или унаследован от базового класса, понимается так:
если элемент имеет спецификатор public, то к нему можно обращаться внутри определенного класса, в методах класса и в дружественных классу функциях и классах, а также через объекты класса в методах класса
если элемент имеет спецификатор private, то к нему можно обращаться только внутри определенного класса, в методах класса и в дружественных классу функциях и классах
если элемент имеет спецификатор protected, то правила обращения такие же как и в случае private, особые свойства проявляются только в реализации собственного механизма наследования.
Рассмотрим, как устроен механизм наследования:
Основные правила:
Спецификатор базово класса в определении производного класса (заданный явно или неявно) |
Спецификатор элемента в базовом классе (заданный явно или неявно) |
Доступ к унаследованному элементу в производном классе |
Возможность обращения к унаследованному элементу через объекты класса вне элементов класса |
private |
private |
нет |
нет |
protected |
private |
нет | |
public |
private |
нет | |
protected |
private |
нет |
нет |
protected |
protected |
нет | |
public |
protected |
нет | |
public |
private |
нет |
нет |
protected |
protected |
нет | |
public |
public |
да |
Таблица 4.1
Рассмотрим иллюстрацию работы этих правил на конкретном примере 2-х иерархично связанных классов:
class point {
public:
double x, y; // координаты точеки
protected:
double vx, vy; // скорость точки
private:
double Ax, Ay; // ускорение точки
public:
point (double x1 = 0.0, double y1 = 0.0, double vx1 = 0.0, double vy1 = 0.0, double Ax1 = 0.0, double Ay1 = 0.0):
x (x1), y (y1), vx (vx1), vy (vy1), Ax (Ax1), Ay (Ay1) { } // это конструктор общего вида играющий роль конструктора умолчания и конструктор приведения типов, конструктор копирования и операция присваивания создаются компилятором
friend ostream & operator << (ostream & out, point p); // прототип функции операции для перегрузки операции вывода “<<”
void print ( ); // прототип метода для вывода на экран поля Ax
}; // конец определения класса point