
- •220300 - Системы автоматизированного проектирования
- •Тема 2. Технологии программирования
- •Тема 2. Технология разработки крупных приложений
- •Структуры
- •Структуры и функции
- •Массивы структур
- •Поиск в массиве структур
- •Вложенность структур
- •Рекурсия
- •Алгоритм быстрой сортировки
- •Массивы структур и бинарные файлы
- •Динамические структуры данных
- •Линейные списки
- •Очереди
- •Контрольная работа
- •Объектно-ориентированное программирование. Классы
- •Конструкторы
- •Перегруженные конструкторы
- •Определение методов класса вне класса
- •Объекты, возвращаемые функцией (методом)
- •Структуры и классы
- •Классы и память
- •Статические данные класса
- •Константные методы
- •Деструкторы
- •Массивы и классы
- •Массивы объектов
- •Строки Строковый тип или стандартный класс string
- •Тип строк AnsiString
- •Перегрузка операций
- •Перегрузка арифметических операций
- •Перегрузка операций сравнения
- •Перегрузка операции приведения типа
- •Преобразования объектов в основные типы и наоборот
- •Преобразование объектов классов в объекты других классов
- •Наследование
- •Конструкторы производного класса
- •Перегрузка функций
- •Иерархия классов
- •Общее и частное наследование. Комбинации доступа
- •Множественное наследование
- •Включение. Классы в классах
- •Виртуальные и дружественные функции
- •Абстрактные классы и чистые виртуальные функции
- •Виртуальные деструкторы
- •Виртуальные базовые классы или устранение неоднозначности при множественном наследовании
- •Дружественные функции
- •Дружественные классы
- •Указатель this
- •Многофайловые программы
- •Распознавание нажатых клавиш
Наследование
Наследование – это процесс создания новых классов, называемых наследниками или производными классами, из уже существующих или базовых классов. Производный класс получает все возможности базового класса и может быть усовершенствован за счёт добавления собственных. Базовый класс при этом остаётся неизменным. Проиллюстрируем взаимосвязь классов при наследовании.
Базовый класс
Производный
класс
Свойства
А и Б доступны |
На одном из прошлых занятий мы разбирали класс Count, в котором использовалась перегруженная операция ++. Допустим теперь нам необходимо, не изменяя этот класс, создать метод для уменьшения счётчика. Допустим на создание и тестирование класса Count было затрачено много времени и желание его не изменять вполне очевидно. Или мы просто не имеем доступа к исходному коду класса, например, если он распространяется как часть библиотеки классов. В этих случаях целесообразно использовать наследование для создания производных классов.
class Count { //базовый класс
protected:
int c;
public:
Count( ) { c=0; }
Count(int t) { c=t; }
int get() const {
return c;
}
Count operator++() {
++c;
return Count(c);
}
};
//---------------------------------------------------------------------------
class CountPr : public Count { // производный класс
public:
Count operator--() {
--c;
return Count(c);
}
};
//---------------------------------------------------------------------------
int main( ) {
CountPr c1; // объект с1 производного класса
cout << "\n c1=" << c1.get();
++c1; ++c1; ++c1;
cout << "\n c1=" << c1.get();
--c1; --c1;
cout << "\n c1=" << c1.get();
getch(); return 0;
}
В данной программе определён новый производный класс CountPr, который включает в себя новый метод уменьшения счётчика и в тоже время наследует (использует) все возможности базового класса Count (его конструкторы и методы).
Строка class CountPr : public Count определяет, что класс CountPr является наследником базового класса. Ключевое слово public определяет, что объект производного класса может иметь доступ к методам базового класса, объявленным как public. Если используется ключевое слово private, то для объектов производного класса нет доступа к членам базового класса.
При создании объекта с1 производного класса происходит его инициализация нулевым значением несмотря на то, что в классе CountPr нет конструктора. Здесь работает принцип – если конструктор производного класса не определён, то будет использоваться подходящий конструктор базового класса. В данном случае используется конструктор без аргументов базового класса Count. Таким образом, использование доступного метода взамен отсутствующего – обычная ситуация, возникающая при наследовании. Действительно, объект с1 класса CountPr, не находя методы в своём классе, использует необходимые методы из базового класса.
Вывод программы:
С1=0
С1=3
С1=1
В данной программе переменная c имеет спецификатор доступа protected. Рассмотрим его предназначение. Методы производного класса имеют доступ к членам (полям и методам) базового класса, если последние имеют спецификатор доступа public или protected. К членам, объявленным как private, доступа нет. Если бы поле count было бы объявлено как public, то это разрешило бы доступ к переменной c из любой функции программы, уничтожив тем самым возможность сокрытия данных. Таким образом, член, объявленный как protected, доступен методам своего класса и методам любого производного класса, но при этом он не будет доступным из функций, не принадлежащих этим классам, например из функции main(). Приведём таблицу, отражающую возможности использования спецификаторов доступа в различных ситуациях.
Таблица 1. Наследование и доступ
Спецификатор доступа |
Доступ из самого класса |
Доступ из производных классов |
Доступ из внешних классов и функций |
public |
Есть |
Есть |
Есть |
protected |
Есть |
Есть |
Нет |
private |
Есть |
Нет |
Нет |
Таким образом, если создаётся класс, который впоследствии будет использоваться как базовый класс при наследовании, то данные, к которым необходимо иметь доступ из производного класса, следует объявлять как protected.
Необходимо помнить, что наследование не работает в обратном направлении. Базовому классу и его объектам недоступны производные классы. То есть, если создать объект с2 класса Count, то он не сможет использовать метод operator--() класса CountPr, а объект производного класса может использовать все методы, как базового класса, так и производного.