Объектно-ориентированное программирование на C++ презентация

Содержание

Слайд 2

Причины возникновения объектно-ориентированного программирования

Слайд 3

С ростом объема кода программы становится невозможным удерживать в памяти все детали

Слайд 4

Необходимо структурировать информацию, выделять главное и отбрасывать несущественное

Слайд 5

Этот процесс называется повышением степени абстракции программы

Слайд 6

Одним из естественных вариантов борьбы со сложностью является алгоритмическая декомпозиция -разбиение задачи на

подзадачи

Слайд 7

Процедурное программирование –
подход, при котором исходная задача разбивается на подзадачи

Слайд 8

Каждая подзадача оформляется в виде функции

Слайд 9

Использование функций - первый шаг к повышению абстракции

Слайд 10

Это позволяет отвлечься от деталей ее реализации, поскольку для вызова функции требуется знать

только ее интерфейс

Слайд 11

Следующий шаг — описание собственных типов данных, позволяющих структурировать и группировать информацию

Слайд 12

Процедурное программирование –
подход, при котором функции и переменные, относящиеся к какому-то конкретному объекту

свободно располагаются в коде и никак между собой не связаны

Слайд 13

Следующий шаг к повышению абстракции – объектно-ориентированный подход

Слайд 14

Объектная декомпозиция –выделение сущностей из предметной области

Слайд 15

Каждая сущность представляется в коде программы в виде класса

Слайд 16

Класс - общее абстрактное описание некоторой сущности

Слайд 17

Объектно-ориентированное программирование –
подход, при котором объекты реального мира представляются в коде в

виде экземпляров классов

Слайд 18

Программа представляет собой совокупность взаимодействующих объектов, имеющих состояние и поведение

Слайд 19

Интернет-магазин бытовой техники

Слайд 20

Объектно-ориентированное программирование –
подход, при котором функции и переменные, относящиеся к конкретному объекту

объединены в коде и тесно связаны между собой

Слайд 21

Концепция «черного ящика» является одной из базовых концепций ООП

Слайд 22

Снаружи объект принято рассматривать как «черный ящик», т.е. некий прибор с кнопками

Слайд 23

Основные понятия ООП

Инкапсуляция
Наследование
Полиморфизм

Слайд 24

Инкапсуляция –
это объединение полей и методов объекта в единое целое - класс

Слайд 25

Синтаксис объявления класса

class имя_класса
{
[private | protected | public]:
тип_поля1 имя_поля1;
тип_поля2 имя_поля2;
тип_поля3

имя_поля3;
...
тип1 имя_метода1(список_параметров)
{
...
}
тип2 имя_метода2(список_параметров)
{
...
}
...
} [список_переменных];

Слайд 26

Способы доступа к компонентам класса

Открытый (public)
Защищенный (protected)
Закрытый (private)

Слайд 27

Пример объявления класса

Слайд 28

Важнейшее требование инкапсуляции - скрытие состояния объекта от внешнего мира

Слайд 29

Инкапсуляция повышает степень абстракции программы

Слайд 30

Данные класса и реализация методов класса находятся ниже уровня абстракции, и для написания

программы информация о них не требуется

Слайд 31

Инкапсуляция позволяет изменить реализацию класса без модификации основной части программы, если интерфейс остался

прежним

Слайд 32

Наследование –
это механизм, который позволяет расширять существующие классы, сохраняя их функциональность и

добавляя им новые свойства и методы

Слайд 33

Полиморфизм –
это механизм, который позволяет использовать одно и тоже имя для решения

нескольких технически разных задач

Слайд 34

Объект как экземпляр класса –
это некоторая уникальная единица, имеющая свои переменные (поля)

и функции (методы), эти переменные обрабатывающие

Слайд 35

Поля объекта - это переменные, описывающие его состояние, а методы - это способ

перевести объект из одного состояния в другое

Слайд 36

Пример создания объекта класса

Слайд 37

Методы-аксессоры

Инспекторы позволяют получить значения полей
Модификаторы позволяют установить значения полей

Слайд 38

Методы-аксессоры

Слайд 39

Конструктор -
это специальный метод класса, который вызывается для конструирования объекта в момент

его создания

Слайд 40

Конструктор не возвращает значение, даже типа void

Слайд 41

Класс может иметь несколько конструкторов с разными параметрами для разных видов инициализации

Слайд 42

Конструктор, вызываемый без параметров, называется конструктором по умолчанию

Слайд 43

Параметры конструктора могут иметь любой тип, кроме этого же класса

Слайд 44

Если программист не указал ни одного конструктора, компилятор создаст его автоматически

Слайд 45

Деструктор –
это специальный метод класса, который вызывается при уничтожении объекта

Слайд 46

Деструктор не принимает никаких параметров и не возвращает значений

Слайд 47

Класс может иметь только один деструктор

Слайд 48

Если деструктор явным образом не определен, компилятор автоматически создаст пустой деструктор

Слайд 49

this – константный указатель на объект класса, который неявно передается в каждый нестатический

метод класса

Слайд 50

Конструктор копирования

Слайд 51

Три ситуации, когда новый объект конструируется путем копирования существующего

Объект создается и инициализируется другим

объектом
Объект передается в функцию по значению
Объект возвращается из функции по значению

Слайд 52

Объект создается и инициализируется другим объектом

Слайд 53

Объект передается в функцию
по значению

Слайд 54

Объект возвращается из функции по значению

Слайд 55

Если в объекте класса есть указатель, адресующий участок динамической памяти, то создается предпосылка

возникновения ошибки на этапе выполнения программы

Слайд 56

Объект создается и инициализируется другим объектом

Слайд 57

Объект передается в функцию
по значению

Слайд 58

Объект возвращается из функции по значению

Слайд 59

При поэлементном копировании указатели двух различных объектов будут адресовать один и тот же

участок динамической памяти

Слайд 60

При разрушении одного из объектов сработает деструктор, который освободит динамическую память

Слайд 61

При разрушении второго объекта снова сработает деструктор, который попытается повторно удалить ранее освобожденный

участок динамической памяти

Слайд 62

Произойдет ошибка этапа выполнения программы

Слайд 63

Для решения данной проблемы необходимо обеспечить класс собственной реализацией конструктора копирования

Слайд 64

В конструкторе копирования необходимо выделить память для указателя вновь создаваемого объекта

Слайд 65

Конструктор копирования

Слайд 66

Статические элементы класса

Слайд 67

Статические поля класса – это глобальные переменные, доступные только в пределах области класса

Слайд 68

Статические поля применяются для хранения данных, общих для всех объектов класса

Слайд 69

Эти поля существуют для всех объектов класса в единственном экземпляре, то есть не

дублируются

Слайд 70

Статические поля класса должны быть определены глобально после описания класса

Слайд 71

В этом случае под них будет выделено соответствующее количество байт памяти

Слайд 72

Статические поля класса

Слайд 73

Статические поля доступны как через имя класса, так и через имя объекта

Слайд 74

На статические поля распространяется действие спецификаторов доступа

Слайд 75

Память, занимаемая статическим полем, не учитывается при определении размера объекта с помощью операции

sizeof

Слайд 76

Статические методы предназначены для обращения к статическим полям класса

Слайд 77

Статическим методам не передается скрытый указатель на объект класса (this)

Слайд 78

Поэтому они могут обращаться непосредственно только к статическим полям и вызывать только статические

методы класса

Слайд 79

Статические элементы класса

Слайд 80

Обращение к статическим методам производится либо через имя класса, либо через имя объекта

Слайд 81

Перегрузка операторов

Слайд 82

Перегрузка операторов – возможность интегрировать пользовательский тип данных в язык программирования

Слайд 83

Перегрузка операторов дает возможность определить собственные действия для стандартных операций, применяемых к объектам

пользовательского типа

Слайд 84

Общий синтаксис перегрузки
операторов

Слайд 85

Ограничения

Нельзя перегружать операции для стандартных типов
Нельзя создавать новые названия операций
Перегрузка не меняет приоритет

операций
В С++ нет неявной перегрузки операций
Для той или иной операции нельзя изменить количество операндов

Слайд 86

Запрещенные к перегрузке операторы

:: - оператор разрешения области видимости
sizeof - оператор определения

размера объекта
. - оператор выбора
?: - условный тернарный оператор

Слайд 87

Способы перегрузки операторов

Функция-операция представляется в виде метода класса
Функция-операция представляется в виде обычной или

дружественной функции

Слайд 88

Дружественные функции

Слайд 89

Функция, объявленная в классе с ключевым словом friend, является дружественной по отношению к

данному классу

Слайд 90

Это означает, что данная функция имеет прямой доступ к скрытым полям класса

Слайд 91

Поскольку дружественной функции не передается указатель this, то она должна принимать в качестве

параметра ссылку на объект класса

Слайд 92

Дружественные функции

Слайд 93

На дружественные функции не распространяются спецификаторы доступа

Слайд 94

Одна функция может быть дружественной сразу нескольким классам

Слайд 95

Другом может быть не только функция, но и метод другого ранее определенного класса

Слайд 96

Дружественные методы

Слайд 97

Если все методы какого-либо класса должны иметь доступ к скрытым полям другого, то

весь класс объявляется дружественным

Слайд 98

Дружественный класс

Слайд 99

Важно понимать, что класс сам определяет, какие функции и классы являются дружественными, а

какие нет

Слайд 100

Шаблоны функций

Слайд 101

Шаблоны используются, когда необходимо создать функции, которые применяют один и тот же алгоритм

к различным типам данных

Слайд 102

Шаблон функции – это обобщенное описание функции

Слайд 103

У такой функции хотя бы один формальный параметр имеет обобщенный тип

Слайд 104

Определение шаблона
функции

Слайд 105

Использование шаблона функции

Слайд 106

В момент вызова функции компилятор автоматически создает специализированную версию функции, где вместо параметра

типа подставляется конкретный тип данных

Слайд 107

Этот процесс называется инстанцированием шаблона или созданием экземпляра шаблона

Слайд 108

Повторный вызов функции с теми же типами параметров не спровоцирует генерацию дополнительной копии

функции, а вызовет уже существующую

Слайд 109

Использование шаблона функции

Слайд 110

Определение шаблона функции не вызывает самостоятельную генерацию кода компилятором

Слайд 111

По этой причине реализацию шаблонов функций следует размещать в заголовочном файле

Слайд 112

Компилятор создает код функции только в момент ее вызова, и генерирует при этом

соответствующую версию функции

Слайд 113

Каждый параметр типа, который встречается в угловых скобках, должен обязательно появиться в списке

параметров функции

Слайд 114

В противном случае произойдет ошибка этапа компиляции

Слайд 115

Определение шаблона
функции

Слайд 116

Перегруженные шаблоны

Слайд 117

Явная специализация шаблона

Слайд 118

Специализация переопределяет шаблон, а обычная нешаблонная функция переопределяет и специализацию, и шаблон

Слайд 120

Важно понимать, что использование шаблонов функций не приводит к уменьшению результирующего объектного кода

Слайд 121

Однако экономит время разработки программы

Слайд 122

Динамические структуры данных

Слайд 123

При решении большинства реальных современных задач для хранения данных приходится использовать динамическую память

Слайд 124

До сих пор мы пользовались обычными динамическими массивами

Слайд 125

При добавлении и удалении элементов массива приходилось перераспределять память

Слайд 126

Динамический массив предполагает такой способ хранения информации, при котором можно получить произвольный доступ

к любому элементу массива по индексу

Слайд 127

Произвольный доступ к элементам является специфической особенностью массива как динамической структуры данных

Слайд 128

Такой способ хранения информации является наиболее часто используемым, но не единственным

Слайд 129

Динамическая структура данных – структура данных определенного формата с определенным способом доступа к

ее элементам и автоматическим расширением размера при необходимости

Слайд 130

Каждая динамическая структура данных имеет определенный набор операций с ее элементами

Слайд 131

Наиболее часто используемые динамические структуры данных

Стек
Очередь
Связный список
Бинарное дерево

Слайд 132

Стек - это динамическая структура данных, которая функционирует по принципу LIFO (Last In

First Out)

Слайд 133

Работа стека организована таким образом, что элементы добавляются и удаляются с одного конца,

называемого вершиной стека

Слайд 134

Кроме того, стек обладает базовым адресом - начальным адресом, по которому стек размещается

в памяти

Слайд 135

Динамическая структура данных «Стек»

Слайд 136

Основные операции над стеком и его элементами

Добавление элемента в стек
Удаление элемента из стека
Просмотр

элемента в вершине стека без удаления
Очистка стека

Слайд 137

Добавление элемента в стек

Слайд 138

Удаление элемента из стека

Слайд 139

Просмотр элемента в вершине стека без удаления

Слайд 140

Очистка стека

Слайд 141

Важно понимать, что стек не определяет новый способ хранения данных в памяти, а

предоставляет новый способ доступа к данным

Слайд 142

Стек широко используются в системном программном обеспечении, включая компиляторы и интерпретаторы

Слайд 143

Очередь - это динамическая структура данных, которая функционирует по принципу FIFO (First In

First Out)

Слайд 144

Очередь чаще всего используется в задачах моделирования различных систем обслуживания

Слайд 145

Разновидности очереди

Классическая очередь
Кольцевая очередь
Очередь с приоритетом

Слайд 146

Классическая очередь

Слайд 147

Кольцевая очередь

Слайд 148

Очередь с приоритетом

Слайд 149

Очередь с приоритетом

Слайд 150

Важно понимать, что очередь не определяет новый способ хранения данных в памяти, а

предоставляет новый способ доступа к данным

Слайд 151

Односвязный список

Слайд 152

Основной способ хранения информации, который используется в программах - это массивы

Слайд 153

При использовании массивов наиболее эффективно выполняются операции доступа к элементам (чтение/изменение)

Слайд 154

В то время как операции вставки/удаления будут значительно менее эффективны

Слайд 155

В задачах, где операции вставки/удаления используются намного чаще, чем операции чтения/изменения, использование массивов

оказывается неэффективным

Слайд 156

Для решения этой проблемы используются такие динамические структуры данных как связные списки

Слайд 157

Односвязный список — это набор элементов, связанных между собой с помощью указателя-связки

Слайд 158

Односвязный список

Слайд 159

Принципиальное отличие списка от массива заключается в том, что элементы списка хранятся не

одним блоком в памяти, а каждый отдельно

Слайд 160

Список вынужден хранить не только сами данные, но дополнительную служебную информацию

Слайд 161

Такой служебной информацией в списке является указатель на следующий элемент (next)

Слайд 162

Этот указатель связывает хранящиеся отдельно в памяти элементы списка в единую динамическую структуру

Слайд 163

Связь между элементами списка однонаправленная, поэтому список называется односвязным

Слайд 164

В качестве точки входа в список используется указатель на его первый элемент, называемый

головой списка (head)

Слайд 165

Вставка узла в определенное место списка

Слайд 166

Удаление узла из списка

Слайд 167

Именно благодаря такой структуре списка, в нем весьма эффективно осуществляются операции вставки/удаления элементов

Слайд 168

Однако, скорость доступа к элементам у списка ниже, чем у массива

Слайд 169

Двусвязный список

Слайд 170

Недостаток односвязного списка – однонаправленная связь между его элементами

Слайд 171

Из первого элемента списка попасть во второй можно, а обратно уже нет

Слайд 172

Вместо этого придется заново перебирать все элементы, начиная с головы списка, что приводит

к потере производительности

Слайд 173

Для решения этой проблемы следует добавить в каждый элемент списка еще одно служебное

поле

Слайд 174

В этом поле будет храниться указатель на предыдущий элемент (previous)

Слайд 175

Тогда из любого элемента списка можно будет попасть не только в следующий за

ним элемент в списке, но и в предыдущий

Слайд 176

Двусвязный список

Слайд 177

Такая структура предоставляет возможность двунаправленно перебирать список

Слайд 178

Первый элемент двусвязного списка называется головой списка (head)

Слайд 179

Последний элемент двусвязного списка называется хвостом списка (tail)

Слайд 180

Вставка узла в определенное место двусвязного списка

Слайд 181

Удаление узла из двусвязного списка

Слайд 182

Бинарные деревья поиска

Слайд 183

Бинарное дерево – это структурированная совокупность узлов, каждый из которых может иметь одного

предка и двух потомков

Слайд 184

Под предком понимают родительский узел, а потомком называют дочерний узел

Слайд 185

Бинарное дерево – это динамическая структура данных, в которой элементы изначально упорядочены

Слайд 186

Каждый узел бинарного дерева помимо данных имеет ключ, который однозначно идентифицирует узел

Слайд 187

Бинарное дерево поиска

Слайд 188

Для каждого узла бинарного дерева в левой ветке содержатся только те ключи, которые

имеют значения, меньшие, чем значение данного узла

Слайд 189

Для каждого узла в правой ветке содержатся ключи, имеющие значения, большие (или равные),

чем значение данного узла

Слайд 190

Бинарное дерево эффективно используется для поиска информации

Слайд 191

Однако, в этом случае бинарное дерево должно быть сбалансированным – расти в ширину,

а не в высоту

Слайд 192

Если бинарное дерево не сбалансировано, то поиск данных будет достаточно долгим

Слайд 193

В отличие от массива бинарное дерево хранит отсортированную информацию не в линейном виде,

а в иерархическом

Слайд 194

Узел, который не имеет предка, является корнем бинарного дерева

Слайд 195

Узел, который не имеет потомков, называется листом

Слайд 196

Бинарное дерево поиска

Слайд 197

Структура узла
бинарного дерева

Слайд 198

Добавление узла в
бинарное дерево

Слайд 199

При добавлении узел вставляется в дерево таким образом, что дерево не нужно специально

сортировать

Слайд 200

Узел сразу вставляется в «правильную» позицию, причем такая позиция единственная

Слайд 201

При удалении узла из дерева возможны три ситуации

Слайд 202

Если удаляемый узел дерева является листом, то удаление такого узла является тривиальной задачей

Слайд 203

Удаление узла из дерева

Слайд 204

Если удаляемый узел имеет только одного потомка, тогда дочерний узел напрямую соединяется с

родительским узлом

Слайд 205

Удаление узла из дерева

Слайд 206

Если удаляемый узел имеет двух потомков, тогда отыскивается следующий узел дерева и данные

из него копируются в удаляемый узел, после чего следующий узел удаляется из дерева

Слайд 207

Удаление узла из дерева

Слайд 208

Агрегация и композиция

Слайд 209

Агрегирование (агрегация) –
это включение объекта (объектов) одного класса в состав объекта другого

класса

Слайд 210

Агрегация — отношение между двумя равноправными объектами, при котором один объект (контейнер) имеет

ссылку на другой объект

Слайд 211

Оба объекта могут существовать независимо: если контейнер будет уничтожен, то его содержимое — нет

Слайд 212

Пример отношения агрегации

Слайд 213

Пример отношения агрегации

Слайд 214

Композиция — более строгий вариант агрегации, когда включаемый объект может существовать только как

часть контейнера

Слайд 215

Если контейнер будет уничтожен, то и включённый объект тоже будет уничтожен

Слайд 216

Пример отношения композиции

Слайд 217

Пример отношения композиции

Слайд 218

Пример отношения агрегации и композиции

Слайд 219

Наследование

Слайд 220

Наследование – механизм языка С++, который позволяет расширять существующие классы, сохраняя их функциональность

и добавляя им новые свойства и методы

Слайд 221

Класс, от которого наследуются называют базовым классом

Слайд 222

Класс, который наследует некоторый класс называют классом-наследником или производным классом

Слайд 223

Таким образом, наследование позволяет повторно использовать уже написанный код, расширяя и дополняя его

при необходимости новыми функциональными возможностями

Слайд 224

Общий синтаксис
наследования

class <имя производного класса>: [спецификатор наследования]
<имя базового класса>
{
<элементы класса>
};
[спецификатор наследования]

=
public | protected | private

Слайд 225

Спецификатор наследования определяет каким будет в производном классе доступ к полям базового класса

Слайд 226

Если спецификатор наследования не указан, то по умолчанию для классов будет private, а

для структур - public

Слайд 227

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

Слайд 228

Спецификаторы доступа

Слайд 229

Важно понимать, что все унаследованные private-поля хотя и недоступны непосредственно в объектах производного

класса, но всё равно содержатся в них

Слайд 230

Конструкторы и деструкторы не наследуются

Слайд 231

При создании объекта производного класса вызываются конструкторы всех классов иерархии, начиная с самого

верхнего и заканчивая конструктором этого производного класса

Слайд 232

Деструкторы, соответственно, вызываются в обратном порядке

Слайд 235

Для инициализации унаследованных полей базового класса в производном классе следует использовать конструктор базового

класса

Слайд 241

В конструкторе производного класса следует явно инициализировать только новые поля, которые не были

унаследованы от базового класса

Слайд 242

При помощи списка инициализаторов мы сообщаем компилятору какой именно конструктор следует вызвать

Слайд 243

Если необходимо изменить функциональность производного класса относительно базового класса, то используется переопределение методов

Слайд 244

Если в производном классе имеется метод с таким же именем и сигнатурой, как

и в базовом классе, такой метод считается переопределённым

Слайд 248

Если в производном классе имеется метод с точно таким же именем как и

в базовом классе, но различной сигнатурой, то такой метод называется замещённым

Слайд 252

Множественное наследование

Слайд 253

При множественном наследовании производный класс наследуется от нескольких базовых классов

Слайд 254

Пример множественного наследования

Слайд 255

При множественном наследовании порядок вызова конструкторов базовых классов определяется не списком инициализаторов, а

порядком, в котором указаны базовые классы при объявлении производного класса

Слайд 256

Порядок вызова конструкторов

Слайд 257

Деструкторы вызываются в порядке, обратном порядку вызова конструкторов

Слайд 258

Главной проблемой множественного наследования являются конфликты имен

Слайд 259

Конфликты имен

Слайд 260

Для решения этой проблемы необходимо использовать операцию разрешения контекста для доступа к полям

в производном классе

Слайд 261

Решение проблемы конфликта имен

Слайд 262

«Ромбовидное» наследование

Слайд 263

Проблема «ромбовидного» наследования состоит в том, что в производном классе D дублируется поле

из класса A

Слайд 264

Для решения проблемы необходимо класс A сделать виртуальным базовым классом и обеспечить его

конструктором по умолчанию

Слайд 265

Решение проблемы «ромбовидного» наследования

Слайд 266

При создании объекта производного класса в цепочке вызовов конструкторов сначала вызываются конструкторы по

умолчанию виртуальных базовых классов, в порядке следования слева направо, а затем все остальные конструкторы

Слайд 267

Полиморфизм

Слайд 268

Механизм раннего связывания

Слайд 270

Механизм раннего связывания

Слайд 271

Поскольку тип объектной переменной известен на этапе компиляции программы, то связывание вызова метода

с самим кодом метода происходит на этапе построения программы

Слайд 272

Такое связывание называется ранним связыванием

Слайд 273

Механизм наследования позволяет записывать адрес объекта производного класса в указатель на базовый класс

Слайд 274

Через указатель на базовый класс можно работать с объектом производного класса, но только

с той частью, которая была унаследована из базового

Слайд 275

Это позволяет абстрагироваться от конкретного объекта, от конкретной реализации

Слайд 276

Это дает возможность выбирать любую реализацию во время выполнения программы

Слайд 277

Т.е. работать с любым объектом через указатель на базовый класс

Слайд 279

При работе с объектом производного класса через указатель на базовый класс связывание вызова

метода с самим кодом метода происходит на этапе построения программы

Слайд 280

В результате вызывается метод класса, соответствующий типу указателя, а не типу объекта, который

адресуется через данный указатель

Слайд 281

Это, по-прежнему, раннее связывание

Слайд 282

При работе с объектом производного класса через указатель на базовый класс желательно, чтобы

связывание вызова метода с самим кодом метода происходило на этапе выполнения программы

Слайд 283

Необходимо, чтобы вызывался метод в соответствии с типом объекта, а не типом указателя,

который адресует данный объект

Слайд 284

Для решения данной проблемы в базовом классе переопределяемый метод объявляется как виртуальный

Слайд 285

В производных классах этот виртуальный метод переопределяется

Слайд 286

Класс, который содержит хотя бы один виртуальный метод, называется полиморфным

Слайд 289

Для каждого класса иерархии, в котором определяется или переопределяется виртуальный метод, компилятор создаёт

таблицу виртуальных функций

Слайд 290

В этой таблице содержатся адреса всех виртуальных методов в порядке их описания в

классе

Слайд 291

Адрес любого виртуального метода имеет в таблице одно и то же смещение

для каждого класса в пределах иерархии

Слайд 292

Каждый объект полиморфного класса содержит дополнительное поле-указатель vptr на таблицу виртуальных функций

Слайд 293

Этот указатель vptr заполняется конструктором при создании объекта

Слайд 294

На этапе компиляции программы все обращения к виртуальным методам заменяются на обращения к

таблице через vptr объекта

Слайд 295

На этапе выполнения в момент обращения к виртуальному методу его адрес выбирается из

таблицы и выполняется вызов

Слайд 296

В этом и заключается механизм позднего связывания

Слайд 297

Механизм позднего
связывания

Слайд 298

Таким образом, вызов виртуального метода, в отличие от обычных методов, выполняется через дополнительный

этап получения адреса метода из таблицы виртуальных функций

Слайд 299

В производных классах переопределённые виртуальные методы не обязательно объявлять с ключевым словом virtual

Слайд 300

Отсюда вытекает правило виртуальности: метод, объявленный виртуальным в некотором классе, остается виртуальным во

всех его потомках

Слайд 301

Если в базовом классе имеется виртуальный метод, то в производном классе метод с

таким же именем и сигнатурой автоматически становится виртуальным

Слайд 302

Виртуальный метод не может быть статическим, однако может быть другом в некотором классе

Слайд 303

Объект, который адресуется через указатель или ссылку и имеет хотя бы один виртуальный

метод, называется полиморфным

Слайд 304

Виртуальный метод, объявленный в базовом классе, наследуется производными классами

Слайд 305

Поэтому переопределять его следует только в том случае, если необходимо задать отличающиеся действия

Слайд 308

Абстрактный базовый класс

Слайд 309

Чаще всего базовые классы предназначены для представления общих понятий, которые предполагается конкретизировать

в производных классах

Слайд 310

Очевидно, что объекты таких классов создавать бессмысленно (например, класс figure)

Слайд 311

Базовый класс важен исключительно как абстрактный класс, определяющий общие принципы работы его

потомков

Слайд 312

В языке C++ существует возможность зафиксировать эту абстрактность на уровне самого языка

Слайд 313

Для этого используются чисто виртуальные функции

Слайд 314

Чисто виртуальный метод –
это метод, который в базовом классе только объявляется,

но не определяется
virtual void calculateArea ()=0;

Слайд 316

Базовый класс, который содержит хотя бы один чисто виртуальный метод называется абстрактным базовым

классом

Слайд 317

Абстрактный класс может использоваться только в качестве базового для других классов — объекты

абстрактного класса создавать нельзя

Слайд 318

Однако можно создавать указатель или ссылку на абстрактный базовый класс

Слайд 319

Абстрактный класс можно рассматривать как заготовку, в которой часть функциональности реализована, а оставшаяся

часть делегирована потомкам

Слайд 320

Важно понимать, что производный класс, который наследуется от абстрактного базового класса, должен переопределить

все чисто виртуальные методы

Слайд 321

В противном случае производный класс также будет считаться абстрактным

Слайд 322

Таким образом, можно создать функцию, параметром которой является указатель на абстрактный класс

Слайд 323

На место этого параметра при выполнении программы может передаваться указатель на объект любого

производного класса

Слайд 324

Это позволяет создавать полиморфные функции, работающие с объектом любого типа в пределах

одной иерархии

Слайд 325

Полиморфная функция

Слайд 326

Таким образом, полиморфизм предполагает один интерфейс и множество реализаций

Слайд 327

Динамическая идентификация
типов (Run-Time Type Identification, RTTI)

Слайд 328

Механизм идентификации типа во время выполнения программы позволяет определять, на какой тип

в текущий момент времени ссылается указатель

Слайд 329

Для доступа к RTTI в стандарт языка введен оператор typeid и класс

type_info

Слайд 330

Формат оператора typeid:
typeid (тип)
typeid (выражение)

Слайд 331

Оператор принимает в качестве параметра имя типа или выражение и возвращает ссылку

на объект класса type_info, содержащий информацию о типе

Слайд 334

Операторы == и != позволяют сравнивать два объекта на равенство и неравенство

Слайд 335

Метод name() возвращает указатель на строку, представляющую имя типа, описываемого объектом класса

type_info

Слайд 336

Полиморфное приведение типов с использованием оператора dynamic_cast

Слайд 337

Оператор dynamic_cast
применяется для преобразования указателей родственных классов иерархии

Слайд 338

Чаще всего dynamic_cast применяется для преобразования указателя базового класса в указатель на

производный

Слайд 339

Формат оператора:
dynamic_cast <тип *> (выражение)

Слайд 340

При этом во время выполнения программы производится проверка допустимости преобразования

Слайд 341

Для того чтобы проверка допустимости могла быть выполнена, аргумент оператора dynamic_cast должен

быть полиморфного типа, т.е. иметь хотя бы один виртуальный метод

Слайд 342

Если преобразование оказалось некорректным, то оно не выполняется, и оператор вернет нулевой

указатель

Слайд 346

Обработка исключительных ситуаций

Слайд 347

Исключение – это временный объект, создаваемый программой в случае возникновения ошибки

Слайд 348

Исключение будет существовать до тех пор, пока его не обработают

Слайд 349

Синтаксис создания (вбрасывания) исключения:
throw значение;

Слайд 350

Исключение может быть объектом любого типа - как стандартного, так и пользовательского

Слайд 351

Механизм обработки исключений - это способ обработки ошибок средствами языка C++

Слайд 352

Синтаксис обработки исключений

try
{
// код, подлежащий проверке на наличие ошибок
throw <выражение>
//генерация

исключения указанного типа
}
catch(<тип_исключения>)
{
//обработка исключения
}

Слайд 353

Файловый ввод/вывод средствами языка С++

Слайд 354

Поток — это абстрактное понятие, относящееся к любому переносу данных от источника

к приемнику

Слайд 355

Поток определяется как последовательность байтов и не зависит от конкретного устройства, с

которым производится обмен

Слайд 356

Физическим устройством может быть клавиатура, монитор, файл, оперативная память, принтер и т.д.

Слайд 357

Обмен с потоком для увеличения скорости передачи данных производится, как правило, через

специальную область оперативной памяти — буфер потока

Слайд 358

Фактическая передача данных выполняется при выводе после заполнения буфера, а при вводе

— если буфер исчерпан

Слайд 359

При этом чтение данных из потока называется извлечением, а вывод данных в

поток — включением

Слайд 360

Вывод данных в поток

Слайд 361

Чтение данных из потока

Слайд 362

По направлению обмена потоки можно разделить на входные, выходные и двунаправленные

Слайд 363

Входные потоки - потоки, из которых читаются данные

Слайд 364

Выходные потоки - потоки, в которые записываются данные

Слайд 365

Двунаправленные потоки - потоки, допускающие как чтение, так и запись

Слайд 366

Стандартная библиотека содержит три класса для работы с файлами:

ifstream — класс

входных файловых потоков
ofstream— класс выходных файловых потоков
fstream — класс двунаправленных файловых потоков

Слайд 367

Эти классы являются производными от классов istream, ostream и iostream соответственно

Слайд 368

Объект класса ifstream представляет собой входной файловый поток для чтения информации из

файла

Слайд 369

Объект класса ofstream представляет собой выходной файловый поток для записи информации в

файл

Слайд 370

Объект класса fstream представляет собой двунаправленный файловый поток для чтения и записи

Слайд 371

Режимы открытия файла

Слайд 372

Стандартная библиотека С++

Слайд 373

Стандартная библиотека шаблонов (STL) (Standard Template Library) - это составная часть стандартной библиотеки

языка С++

Слайд 374

STL - это набор шаблонных классов и функций общего назначения, реализующих наиболее популярные

структуры данных и часто употребительные алгоритмы работы с ними

Слайд 375

Архитектура STL была разработана Александром Степановым и Менг Ли

Слайд 376

STL состоит из следующих компонентов:
контейнеры (containers)
адаптеры (adaptors)
итераторы (iterators)
алгоритмы (algorithms)
функторы (functors)
предикаты (predicates)

Слайд 377

Контейнер предназначен для хранения набора объектов в памяти

Слайд 378

Два основных типа контейнеров: последовательные и ассоциативные

Слайд 379

Последовательный контейнер – упорядоченная коллекция, в которой каждый элемент имеет определенную позицию (vector,

list)

Слайд 380

Позиция зависит от места вставки, но не зависит от значения элемента

Слайд 381

Ассоциативный контейнер –коллекция элементов, в которой позиция элемента зависит от его значения и

выбранного критерия сортировки (map, set)

Слайд 382

Такой контейнер всегда находится в отсортированном состоянии, что ускоряет выполнение поиска

Слайд 383

Адаптер – специализированный контейнер, который предоставляет определенный интерфейс для доступа к данным (stack,

queue)

Слайд 384

Итератор – это специальный указатель, который используется для перемещения по контейнеру и для

манипулирования объектами, находящимися в контейнере

Слайд 385

Итераторы делятся на 5 категорий:

итератор ввода
итератор вывода
прямой итератор
двусторонний итератор
итератор произвольного

доступа

Слайд 386

Итератор ввода (InputIterator) перемещается только вперед и поддерживает только чтение

Слайд 387

Итератор вывода (OutputIterator) перемещается только вперед и поддерживает только запись

Слайд 388

Прямой итератор (ForwardIterator) перемещается только вперед, позволяет выполнять чтение и запись

Слайд 389

Двусторонний итератор (BidirectionalIterator) - прямой итератор, который поддерживает перебор элементов в обратном порядке

Слайд 390

Итератор произвольного доступа (RandomAccessIterator) имеет все свойства двустороннего итератора, а также поддерживает произвольный

доступ к элементам

Слайд 391

Алгоритмы – функции, которые используются для обработки элементов в контейнере (например, сортировка, поиск)

Слайд 392

Алгоритмы используют итераторы

Слайд 393

Так как каждый класс контейнера имеет итератор, один и тот же алгоритм может

работать с различными контейнерами

Слайд 394

Функторы – это объекты, действующие как функции, они могут быть объектами класса или

указателями на функцию

Слайд 395

Функторы позволяют выполнять конфигурирование алгоритмов для специального использования

Слайд 396

Предикаты - функции, которые проверяют, удовлетворяет ли объект заданным критериям, и возвращают значение

типа bool
Имя файла: Объектно-ориентированное-программирование-на-C++.pptx
Количество просмотров: 23
Количество скачиваний: 0