Основные положения
Иерархия классов
Пример наследования
Многоуровневое наследование
Пример иерархии классов – библиотека потокового ввода-вывода C++
Особенности наследования
Плюсы и минусы наследования
Ложные аналогии
Механизм наследования классов
Синтаксис наследования в языке С++
Модификаторы наследования
Модификаторы доступа
Модификаторы доступа в ситуации без наследования
Модификаторы доступа в ситуации с наследованием
Наследование и доступ
Модификаторы наследования vs Модификаторы доступа
Основные положения наследования
Наследование членов базового класса в производном классе
Конструкторы при наследовании
Конструкторы при наследовании
Конструкторы при наследовании
Деструкторы при наследовании
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Наследование при работе с классом first
Конструкторы производного класса
Конструкторы производного класса
Конструкторы производного класса
Конструкторы производного класса
Конструкторы производного класса
Перегрузка методов базового класса в производном классе
Перегрузка методов базового класса в производном классе
Перегрузка методов базового класса в производном классе
Иерархия классов
Иерархия классов
Иерархия классов Иерархия классов Вопрос: какие методы getdata() будут вызывать объекты m1, p1, p2 и cw1 ?
Иерархия классов
1.34M
Category: programmingprogramming

Лекция 5 Наследование Часть 1

1.

Санкт-Петербургский государственный
архитектурно-строительный университет
кафедра информационных технологий
Объектно-ориентированное программирование
Тема 5
Наследование. Часть 1
Букунов Сергей Витальевич
к.т.н., доцент, доцент

2. Основные положения

Наследованием называется механизм, позволяющий одному классу
(производному классу, подклассу) наследовать структуру данных и
поведение (методы) другого (базового класса, суперкласса) класса.
Наследование – это процесс создания новых классов, называемых
наследниками или производными классами, из уже существующих
(базовых) классов.
Базовый класс – это любой класс, который используется в качестве
основы для определения другого класса.
2

3. Иерархия классов

Наследование используется для отработки отношений иерархии в
объектном подходе: все общие свойства различных сущностей
объединены в некотором базовом (родительском) классе, а производные
классы наследуют все его свойства, добавляя свои собственные свойства
и поведение.
3

4. Пример наследования

UML-диаграмма иерархии классов
4

5. Многоуровневое наследование

от одного базового класса можно унаследовать любое количество
производных классов;
производный класс может выступать в роли базового класса для других
классов.
класс Cat является прямым наследником класса Animal и непрямым
наследником класса Organism;
класс Organism является прямым базовым классом для классов Animal и
Plant и непрямым базовым классом для классов Cat и Dog.
5

6. Пример иерархии классов – библиотека потокового ввода-вывода C++

класс ios является базовым классом для всех потоковых классов;
классы istream и ostream являются наследниками класса ios и предназначены для ввода/вывода;
класс iostream – наследник обоих классов istream и ostream (пример множественного наследования;
класс ifstream является производным классом от класса istream и предназначен для считывания данных из файлов;
класс ofstream является производным классом от класса ostream и предназначен для записи данных в файл.
6

7. Особенности наследования

механизм наследования работает только в одну сторону, а
именно от производного класса к базовому. Пример: инженер –
это человек. Обратное же неверно: человек – это
необязательно инженер.
назначение наследования в объектно-ориентированном
программировании такое же, как и у функций в процедурном
программировании – сократить размер кода и упростить связи
между элементами программы.
разработанный класс может быть использован в других
программах. Это свойство называется возможностью
повторного использования кода. Аналогичным свойством в
процедурном программировании обладают библиотеки
функций, которые можно включать в различные программные
проекты.
7

8. Плюсы и минусы наследования

Главная польза от наследования – возможность повторного
использования существующего кода.
Пример. Постоянные обновления версий различного ПО
напрямую связаны с использованием механизма наследования.
Вносить так часто изменения в таких количествах в процедурную
программу без нарушения ее работоспособности было бы очень
проблематично.
Главная «расплата» за наследование – производные классы
наследуют все свойства и методы базового класса, т.е. нельзя
исключить из производного класса метод базового класса (если,
например, он там не нужен).
8

9. Ложные аналогии

Отношения «класс – объект» и «базовый класс – производный
класс» – это «две большие разницы».
Объекты класса представляют собой воплощение свойств и
методов, присущих классу, к которому они принадлежат.
Производные классы имеют свойства как унаследованные от
базового класса, так и свои собственные.
9

10. Механизм наследования классов

10

11. Синтаксис наследования в языке С++

A a; // создали объект a базового класса A
B b; // создали объект b производного класса B
a.MethodA(); // объект a базового класса вызывает метод базового класса
b.MethodB(); // объект b производного класса вызывает метод производного класса
b.MethodA(); // объект b производного класса вызывает метод базового класса
a.MethodB(); // Ошибка !!! Объект a базового класса вызывает метод производного класса
11

12. Модификаторы наследования

Модификатор наследования определяет видимость наследуемых
полей и методов (т.е. полей и методов базового класса) для
производного класса и его возможных потомков. Таким образом
определяется, какие права доступа к полям и методам классародителя будут «делегированы» классу-потомку.
При реализации наследования область видимости принадлежащих
базовому классу данных и методов определяется одним из трех
модификаторов доступа:
private (закрытый);
public (открытый);
protected (защищенный).
12

13. Модификаторы доступа

Модификатор доступа private описывает закрытые члены класса,
доступ к которым имеют только методы-члены этого класса.
Модификатор доступа public предназначен для описания
общедоступных элементов, доступ к которым возможен из любого
места программы, где доступен объект этого класса.
Модификатор доступа protected используется в тех случаях, когда
необходимо, чтобы некоторые члены базового класса оставались
закрытыми для внешнего окружения, но были бы доступны из
производного класса.
Вывод: при создании класса, который в дальнейшем будет
использоваться в качестве базового класса при наследовании,
данные, к которым нужно будет иметь доступ из производных
классов, следует объявлять со спецификатором доступа protected.
13

14. Модификаторы доступа в ситуации без наследования

14

15. Модификаторы доступа в ситуации с наследованием

15

16. Наследование и доступ

16

17. Модификаторы наследования vs Модификаторы доступа

В языке С++ одни и те же ключевые слова используются и в
качестве модификаторов наследования и в качестве модификаторов
доступа.
Модификаторы наследования:
Модификаторы доступа:
- private
- private
- public
- public
- protected
- protected
class figure { …};
class circle : public figure
{ …};
class figure
{ public: int color;

};
17

18. Основные положения наследования

каждый объект производного класса включает в себя объект
базового класса, т.е. состоит из двух частей (своей части и
«базовой» части);
общедоступные (public) элементы базового класса являются
общедоступными элементами производного класса;
закрытые (private) элементы базового класса являются частью
производного класса, но обращаться к ним можно только
посредством общедоступных (public) и защищенных (protected)
методов базового класса;
при наследовании базовый класс остается неизменным;
от одного базового класса можно унаследовать любое количество
производных классов;
производный класс может выступать в роли базового класса для
других классов.
18

19.

Вопрос: какие члены базового класса наследуются в производном
классе, а какие не наследуются ?
19

20. Наследование членов базового класса в производном классе

20

21. Конструкторы при наследовании

21

22. Конструкторы при наследовании

При реализации наследования конструкторы базового и/или
производного класса могут иметь аргументы.
Если аргументы нужны только конструктору производного класса,
они передаются обычным образом.
Если требуется передать какие-либо аргументы родительскому
конструктору, для этого используется расширенная запись
конструктора производного класса:
Конструктор производного класса (список формальных аргументов):// Конструктор производного
Конструктор базового класса (список формальных аргументов)
// вызывает конструктор
{
// базового класса
… // тело конструктора производного класса
}
22

23. Конструкторы при наследовании

списки аргументов родительского и дочернего конструкторов
могут совпадать, а могут и отличаться. Например, конструктор
производного класса часто принимает некоторые аргументы
только для того, чтобы передать их конструктору базового класса;
если в базовом классе есть перегруженный оператор
присваивания, то он не наследуется производными классами. При
этом присваивание объектов производного класса не будет
вызывать ошибку – в этом случае выполняться будет не
перегруженный оператор базового класса, а присваивание по
умолчанию (т.е. будет запускаться конструктор копирования по
умолчанию производного класса), т.е. побитовое копирование
свойств объекта.
23

24. Деструкторы при наследовании

При реализации наследования в случае наличия деструкторов в
базовом и производном классах при уничтожении
объекта
производного класса деструкторы вызываются в обратном порядке:
сначала вызывается деструктор производного класса, т.е.
уничтожается часть объекта, принадлежащая производному
классу;
затем вызывается деструктор базового класса, т.е. уничтожается
часть объекта, принадлежащая базовому классу.
24

25. Наследование при работе с классом first

Задача. Необходимо добавить возможность осуществлять операции
префиксного декрементирования с объектами класса first.
Вопрос: какие у нас есть варианты ?
25

26. Наследование при работе с классом first

Вариант №1. Модифицировать класс first, добавив в состав методов
класса соответствующий метод operator --().
Вариант №2. Создать новый класс, производный от класса first, и
добавить метод operator --() в состав методов этого производного
класса.
Вопрос: какие у нас могут быть мотивы для того, чтобы
использовать для решения этой задачи вариант №2 ?
26

27. Наследование при работе с классом first

Мотив №1. Класс first прекрасно работает, а на его отладку было
затрачено много времени и сил (предположим, что это так).
Мотив №2. Доступ к базовому классу first у нас отсутствует
(например, класс first распространяется как часть библиотеки
классов), следовательно прописать в нем какой-либо новый метод
мы не можем.
27

28. Наследование при работе с классом first

Вопрос: что не нравится компилятору ?
28

29. Наследование при работе с классом first

Ответ: при любом типе наследования у производного класса нет
доступа к закрытым (private) членам базового класса.
Вопрос: как решить проблему ?
29

30. Наследование при работе с классом first

Вопрос: почему у метода класса second тип возвращаемого значения first ?
30

31. Наследование при работе с классом first

Ответ: потому что в классе second отсутствует конструктор.
31

32. Наследование при работе с классом first

Вопрос: почему в производном классе можно вызвать конструктор
базового класса ?
32

33. Наследование при работе с классом first

Ответ: потому что вcе методы из public-секции базового класса
доступны производному классу.
33

34. Наследование при работе с классом first

Вопрос: какую из операций в функции main() не пропустит компилятор ?
int main()
{
first f1; // создаем объект базового класса
second s1; // создаем объект производного класса
++f1; // инкрементируем объект базового класса
++s1; // инкрементируем объект производного класса
--f1; // декрементируем объект базового класса
--s1; // декрементируем объект производного класса
}
34

35. Наследование при работе с классом first

Вопрос: почему ++s1 можно, а --f1 нельзя ?
35

36. Наследование при работе с классом first

Ответ: потому что наследование работает только в одном
направлении: от производного класса к базовому:
производный класс знает всё о базовом классе;
базовый класс не знает о производном классе ничего.
36

37. Наследование при работе с классом first

Вопрос: что мы увидим на экране и почему ?
37

38. Наследование при работе с классом first

Ответ: при отсутствии конструктора в производном классе
компилятор использует конструктор базового класса без
аргументов.
38

39. Конструкторы производного класса

Вопрос: что не нравится компилятору ?
39

40. Конструкторы производного класса

Вопрос: что не нравится компилятору ?
40

41. Конструкторы производного класса

Ответ: при инициализации объекта s2 компилятор пытается
использовать конструктор базового класса без аргументов (т.е.
конструктор first()).
Вопрос: как решить проблему ?
41

42. Конструкторы производного класса

Следствие №1. В функции main() всё хорошо.
Следствие №2. Метод operator--() производного класса имеет тип
возвращаемого значения second, а не first (что более естественно).
42

43. Конструкторы производного класса

Замечание №1. В данном примере конструкторы производного класса для
инициализации полей объектов вызывают конструкторы базового класса .
Замечание №2. Кроме вызова конструктора базового класса конструктор
производного класса может выполнять и свои операции (просто в данном
43
случае этого не требуется).

44. Перегрузка методов базового класса в производном классе

При использовании наследования методам производного класса
можно давать те же названия, что и методам базового класса. Т.е. в
этом случае может иметь место перегрузка функций.
Такая возможность может понадобиться в том случае, если в
программе для объектов базового и производного классов
используются одинаковые вызовы.
Общее правило: если названия методов базового и производного
классов совпадают, то при вызове метода для объекта производного
класса по умолчанию будет вызван метод производного класса. В
этом случае говорят, что метод производного класса перегружает
метод базового класса.
Вопрос. Какой метод будет вызван по умолчанию для объекта
базового класса ?
44

45. Перегрузка методов базового класса в производном классе

Вопрос. Может ли объект производного класса вызвать метод
базового класса в том случае, если названия методов обоих классов
совпадают ?
45

46. Перегрузка методов базового класса в производном классе

Ответ: может, для этого необходимо явно вызвать метод базового
класса.
46

47. Иерархия классов

Механизм наследования может использоваться не только для
добавления новых возможностей существующим классам, но и для
построения иерархии классов на этапе разработки программы.
47

48. Иерархия классов

Вопрос: почему в данном примере поля данных в базовом классе (класс
employee) не обязательно объявлять в защищенной (protected) секции, а
48
можно объявить в закрытой (private) секции ?

49. Иерархия классов Иерархия классов Вопрос: какие методы getdata() будут вызывать объекты m1, p1, p2 и cw1 ?

Иерархия классов
Вопрос: какие методы getdata() будут вызывать объекты m1, p1, p2 и cw1 ?
49

50. Иерархия классов

Замечание. В программе не создано ни
одного объекта базового класса employee
(но, в принципе, его можно создать).
Класс employee использовался только для
того, чтобы стать базовым классом для
других классов.
Такие классы иногда ошибочно называют
абстрактными классами.
50

51.

Санкт-Петербургский государственный
архитектурно-строительный университет
кафедра информационных технологий
Автор:
Букунов Сергей Витальевич
pmi@spbgasu.ru
English     Русский Rules