Методы программирования 2. ООП Л. 01.
Введение в ООП. Мееров И.Б.Методы программирования
(2 семестр)
Раздел 2. Лекция 07 Наследование
Нижегородский государственный университет
им. Н.И. Лобачевского
Факультет вычислительной математики и кибернетики
Методы программирования
(2 семестр)
Раздел 2. Лекция 07 Наследование
Нижегородский государственный университет
им. Н.И. Лобачевского
Факультет вычислительной математики и кибернетики
Краткое содержание предыдущей серии
Перегрузка операций – специальный синтаксический механизм C++, который позволяет использовать стандартные операции языка не только для переменных базовых типов, но и для объектов.
При этом имеется возможность указать, каким именно образом операции должны отрабатывать.
Перегрузка операций – написание специальных функций, отвечающих за выполнение той или иной операции.
Дальнейшее изучение
Сегодня мы изучим, как в C++ реализуется принцип наследования.
Итак, за дело!
Выделение абстракций
Объектный подход подразумевает выделение абстракций в предметной области (классы).
1
2
3
4
Выделение абстракций. Основные достижения
Разобрались, с чем имеем дело.
Проблема моделирования
Важная проблема: типов абстракций (классов) слишком много. Чаще всего их настолько много, что мы не можем одновременно удерживать в голове информацию о них.
Следствие: тяжело разобраться с тем, как решать задачу.
Проблема моделирования.
Решение, часть I
Важная проблема: типов абстракций (классов) слишком много. Чаще всего их настолько много, что мы не можем одновременно удерживать в голове информацию о них.
Следствие: тяжело разобраться с тем, как решать задачу.
Решение, часть I: инкапсуляция позволяет скрыть внутренние детали абстракций и уменьшить объем информации, необходимый для понимания задачи.
Проблема моделирования.
Решение, часть II
Важная проблема: типов абстракций (классов) слишком много. Чаще всего их настолько много, что мы не можем одновременно удерживать в голове информацию о них.
Следствие: тяжело разобраться с тем, как решать задачу.
Решение, часть II: что делать со сложными задачами известно еще с древних времен. Один из основных принципов: “Разделяй и властвуй!”.
Проблема моделирования.
Решение, часть II. “Разделяй и властвуй!”
Примечание: принцип приобрел некоторый специальный смысл в математике. Под таким заголовком можно встретить описание целого класса алгоритмов, решающих различные задачи (пример: вычислительная геометрия).
Модульная структура позволяет объединять абстракции (классы) в группы (файлы), тем самым наводя некоторый порядок и позволяя разрабатывать программу по частям.
Но этого оказывается недостаточно.
Проблема моделирования. Иерархия
Решение: по мнению специалистов, “значительное упрощение в понимании сложных задач достигается за счет образования из абстракций иерархической структуры” (Grady Booch).
Иерархия
Иерархия – упорядочение абстракций, расположение их по уровням.
Обнаружение иерархий существенно упрощает понимание задачи. Теперь задачу можно понимать на разных уровнях, постепенно спускаясь к все более и более детальному представлению.
Виды иерархий
Можно обнаружить 2 вида иерархий:
“Это есть…”
“Быть частью”.
Пример:
Круг и точка.
Два варианта представления:
Круг – это такая точка, у которой, кроме того, что есть у точки, есть еще радиус
Круг – это точка + радиус.
Виды иерархий
Можно обнаружить 2 вида иерархий:
“Это есть…”
“Быть частью”.
Пример:
Треугольник.
Два варианта представления:
Треугольник – это такая точка, у которой, кроме того, что есть у точки, есть еще 2 точки
Треугольник – это точка + точка + точка.
Виды иерархий
Можно обнаружить 2 вида иерархий:
“Это есть…”
“Быть частью”.
Пример:
Звери.
Иерархия абстракций:
Животное – умеет перемещаться.
Птица – Животное, которое умеет летать.
Соловей – Птица, которая умеет не только летать, но еще и петь…
Наследование и агрегация
ЭТО ЕСТЬ…
БЫТЬ ЧАСТЬЮ…
НАСЛЕДОВАНИЕ
АГРЕГАЦИЯ
Примеры иерархий.
Структура персонального компьютера
ПК
Системный блок
Монитор
Периферия
…
Материнская плата
…
…
ЦПУ
…
Уровни абстракции
Уровни абстракции
агрегация
Примеры иерархий.
Координатная плоскость
Точка: (x, y)
Круг: (x, y, R)
Эллипс: (x, y, R1, R2)
Квадрат: (x, y, a)
Прямоугольник: (x, y, a, b).
Треугольник:(x1,y1, x2,y2, x3,y3)
Координатная плоскость
(набор фигур)
Агрегация
Наследование
ТОЧКА (x, y)
КРУГ (R)
ФИГУРА
ИЛИ:
ТОЧКА (x, y)
КРУГ (R)
КВАДРАТ (a)
…
ТРЕУГОЛЬНИК = ТОЧКА + ТОЧКА + ТОЧКА
Реализация агрегации в C++
С этим мы уже знакомы.
Синтаксически агрегация представляет собой использование объекта одного класса в качестве поля другого класса.
Реализация агрегации в C++. Пример _1
class TPoint {
private:
int visible;
public:
int x, y;
TPoint(int _x, int _y);
void Show();
void Hide();
int IsVisible() const {return visible;}
};
Реализация агрегации в C++. Пример _2
class TTriangle {
private:
int visible;
public:
TPoint a, b, c;
TTriangle(TPoint _a, TPoint _b, TPoint _c);
void Show();
void Hide();
int IsVisible() const {return visible;}
};
Наследование в C++. Основные идеи
Новые классы образуются при помощи старых, заимствуя все поля методы и реализуя некоторую новую функциональность.
Классы, находящиеся в вершине иерархии, объединяют в себе некоторое количество свойств, общих для всей иерархии.
Постепенно, спускаясь по иерархии вниз, мы добиваемся все большей детализации.
Наследование в C++.
Понятие схемы выводимости
Схема выводимости – схема наследования классов.
схема выводимости
Терминология
Существует 3 варианта терминологии:
предок – потомок;
суперкласс – подкласс.
базовый класс – подчиненный класс.
Предок
Потомок
Синтаксис определения класса-потомка
class <Имя_класса>: [<Спецификатор>] <Базовый класс> {
};
Примеры:
class TPoint: TFigure {…};
class TPoint: public TFigure {…};
class TPoint: private TFigure {…};
class TPoint: protected TFigure {…};
По умолчанию подразумевается
спецификатор доступа private
Спецификаторы доступа
private, public, protected
Спецификаторы доступа используются не только для определения областей доступа внутри класса, но и для определения вида наследования
(public-, private- и protected-наследование).
Вид наследования определяет, что происходит с видом доступа в производных классах.
Для одиночного класса спецификатор доступа
protected означает то же самое, что и private
Спецификаторы доступа
private, public, protected
Анализ таблицы
Как видно из таблицы, private элементы базового класса в производном классе недоступны вне зависимости от ключа. Обращение к ним может осуществляться только через методы базового класса.
Элементы protected при наследовании с ключом private становятся в производном классе private, в остальных случаях права доступа к ним не изменяются.
Доступ к элементам public при наследовании становится соответствующим ключу доступа.
Пример
Создадим классы геометрических фигур на плоскости.
Точка: x, y, visible.
class TPoint {
private:
int x, y, visible;
public:
TPoint(int _x = 0, int _y = 0, _vis = 0) {
x = _x; y = _y; visible = _vis;
}
~TPoint() {};
int IsVisible() const { return visible; }
void Show() {
if (!visible) {
printf("%d %d ", x, y); visible = 1; }
}
};
Пример
Создадим классы геометрических фигур на плоскости.
Круг: x, y, r, visible.
class TCircle {
private:
int x, y, r, visible;
public:
TCircle(int _x = 0, int _y = 0, _r = 0, _vis = 0) {
x = _x; y = _y; r = _r; visible = _vis;
}
~TCircle() {};
int IsVisible() const { return visible; }
void Show() {
if (!visible) {
printf("%d %d %d ", x, y, r); visible = 1; }
}
};
Анализ примера
Обнаруживаем, что у нас несколько раз написано одно и то же. По смыслу круг – это точка, у которой есть радиус (наследование).
Реализуем новый класс TCircle, унаследовав его от TPoint.
Посмотрим, какие проблемы при этом появляются.
TCircle:
Данные: радиус, все остальное придет от TPoint.
Методы: изменяются конструктор, деструктор, Show(). IsVisible() приходит от TPoint.
Пример
class TCircle: public TPoint {
private:
int r;
public:
TCircle(int _x = 0, int _y = 0, _r = 0, _vis = 0)
{
x = _x; y = _y; r = _r; visible = _vis;
}
~TCircle() {};
void Show() {
if (!visible) {
printf("%d %d %d ", x, y, r); visible = 1; }
}
};
Все хорошо?
Пример
class TCircle: public TPoint {
private:
int r;
public:
TCircle(int _x = 0, int _y = 0, _r = 0, _vis = 0)
{
x = _x; y = _y; r = _r; visible = _vis;
}
~TCircle() {};
void Show() {
if (!visible) {
printf("%d %d %d ", x, y, r); visible = 1; }
}
};
Ошибка!
поле visible
скрыто
Пример. Исправления в TPoint
class TPoint {
protected:
int x, y, visible;
public:
TPoint(int _x = 0, int _y = 0, _vis = 0) {
x = _x; y = _y; visible = _vis;
}
~TPoint() {};
int IsVisible() const { return visible; }
void Show() {
if (!visible) {
printf("%d %d ", x, y); visible = 1; }
}
};
Пример. TCircle без исправлений
class TCircle: public TPoint {
private:
int r;
public:
TCircle(int _x = 0, int _y = 0, _r = 0, _vis = 0)
{
x = _x; y = _y; r = _r; visible = _vis;
}
~TCircle() {};
void Show() {
if (!visible) {
printf("%d %d %d ", x, y, r); visible = 1; }
}
};
Анализ примера
Заметим, что ошибка проявлялась не только относительно поля visible, но и относительно полей x, y.
Вопрос: как быть? Объявлять все поля со спецификатором protected?
Ответ: нет! Есть средства правильной реализации. Они заключаются в том, что Вы можете вызывать методы предка, в т.ч. и для конструирования объектов.
Некоторые правила наследования _1
Конструкторы не наследуются, поэтому производный класс должен иметь собственные конструкторы. Порядок вызова конструкторов определяется приведенными ниже правилами.
Если в конструкторе производного класса явный вызов конструктора базового класса отсутствует, автоматически вызывается конструктор базового класса по умолчанию (то есть тот, который можно вызвать без параметров).
Некоторые правила наследования _2
Для иерархии, состоящей из нескольких уровней, конструкторы базовых классов вызываются начиная с самого верхнего уровня. После этого выполняются конструкторы тех элементов класса, которые являются объектами, в порядке их объявления в классе, а затем исполняется конструктор класса.
Некоторые правила наследования _3
Если конструктор базового класса требует указания параметров, он должен быть явным образом вызван в конструкторе производного класса в списке инициализации.
Пример. Исправления в TPoint
class TPoint {
private:
int x, y;
protected:
visible;
public:
TPoint(int _x = 0, int _y = 0, _vis = 0):
x(_x), y(_y), visible(_vis) {}
~TPoint() {};
int IsVisible() const { return visible; }
void Show() {
if (!visible) {
printf("%d %d ", x, y); visible = 1; }
}
};
Пример. Исправления вTCircle
class TCircle: public TPoint {
private:
int r;
public:
TCircle(int _x = 0, int _y = 0, _r = 0, _vis = 0):
TPoint(_x, _y, _vis), r(_r) {}
~TCircle() {};
void Show() {
if (!visible) {
printf("%d %d %d ", x, y, r); visible = 1; }
}
};
Анализ примера
Заметим, что в методе Show переписана часть метода Show для класса TPoint.
Изменения:
class TCircle: public TPoint {
private:
int r;
public:
TCircle(int _x = 0, int _y = 0, _r = 0, _vis = 0):
TPoint(_x, _y, _vis), r(_r) {}
~TCircle() {};
void Show() {
if (!visible) {
TPoint::Show();
printf("%d ", r);
}}
};
вызов
перекрытого
метода
Некоторые правила наследования _4
Операция присваивания не наследуется, поэтому ее необходимо переписывать явно в каждом выведенном классе.
Некоторые правила наследования _5
Деструкторы не наследуются, и если программист не описал в производном классе деструктор, он формируется по умолчанию и вызывает деструкторы всех базовых классов.
В отличие от конструкторов, при написании деструктора производного класса в нем не требуется явно вызывать деструкторы базовых классов, поскольку это будет сделано автоматически.
Для иерархии классов, состоящей из нескольких уровней, деструкторы вызываются в порядке, строго обратном вызову конструкторов, сначала вызывается деструктор класса, затем – деструкторы элементов класса, а потом деструктор базового класса.
Следующая тема
Далее мы рассмотрим, как реализуется в C++ механизм виртуальных методов.
Павловская Т.А. C/C++ Программирование на языке высокого уровня.
Ален И. Голуб. Правила программирования на C/C++.
Гради Буч. Объектно-ориентированный анализ и проектирование с примерами приложений на C++.
Из книг заимствованы различные идеи, элементы текста.
http://lye.upnet.ru
http://xaxa.h1.ru/jokes.html
Если не удалось найти и скачать доклад-презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:
Email: Нажмите что бы посмотреть