- •1 4 Семинар 1. Классы
- •Что принесло с собой ооп
- •1 6 Семинар 1. Классы
- •От структуры — к классу
- •Задача 1.1. Поиск в массиве структур
- •1 8 Семинар 1. Классы
- •Инициализаторы конструктора
- •28 Семинар 1. Классы
- •Конструктор копирования
- •Перегрузка операций инкремента
- •Задача 1.1. Поиск в массиве структур 31
- •1 Является переменной встроенного типа, форма инкремента безразлична:
- •Статические элементы класса
- •3 4 Семинар 1. Классы
- •4 0 Семинар 1. Классы
- •Задача 1.2. Реализация класса треугольников 45
1 6 Семинар 1. Классы
Наследование •— механизм получения нового класса из существующего. Производный
класс создается путем дополнения или изменения существующего класса.
Благодаря этому реализуется концепция повторного использования кода.
С помощью наследования может быть создана иерархия родственных типов, которые
совместно используют код и интерфейсы.
Полиморфизм дает возможность создавать множественные определения для операций
и функций. Какое именно определение будет использоваться, зависит от
контекста программы. Вы уже знакомы с одной из разновидностей полиморфизма
в языке C++ — перефузкой функций. Программирование с ютассами предоставляет
еще две возможности: перегрузку операций и использование так называемых
виртуальных методов. Перегрузка операций позволяет применять для собственных
классов те же операции, которые используются для встроенных типов C++.
Виртуальные методы обеспечивают возможность выбрать на этапе выполнения
нужный метод среди одноименных методов базового и производного классов.
Кроме наследования, классы могут находиться также в отношении агрегации^:
например, когда в составе одного класса имеются объекты другого класса. Совместное
использование наследования, композиции и полиморфизма лежит в основе
элегантных проектшлх решений, обеспечивающих наибольшую простоту МОДРГ-
фикации программы (эта тема будет рассмотрена на втором семинаре).
Ну и, наконец, отметим, что в реальном проекте, разработанном на базе объектно-
ориентированной декомпозиции, находится место и для алгоритмически-
ориентированной декомпозиции (например, при реализации сложных методов).
От структуры — к классу
Прообразом класса в C++ является структура в С. В то же время в C++ структура
обрела новые свойства и теперь является частным видом класса, все элементы
которого по умолчанию являются открытыми. Со структурой struct в C++ можно
делать все, что можно делать с классом. Тем не хменее в C++ структуры обычно
используют лишь для удобства работы с небольшими наборами данных без
какого-либо собственного поведения.
Новые понятия легче изучать, отталкиваясь от уже освоенного материала. Давайте
возьмем задачу 6.1 из первой книги практикума и посмотрим, что можно
с ней сделать, применяя средства ООП.
Задача 1.1. Поиск в массиве структур
В текстовом файле хранится база отдела кадров предприятия. На предприятии
100 сотрудников. Каждая строка файла содержит запись об одном сотруднике.
Формат записи: фамилия и инициалы (30 позиций, фамилия должна начинаться с
первой позиции), год рождения (5 позиций), оклад (10 позиций). Написать программу,
которая по заданной фамилии выводит на экран сведения о сотруднике,
подсчитывая средний оклад всех запрошенных сотрудников.
Более подробно об этом — также на втором семинаре.
Задача 1.1. Поиск в массиве структур 17
Напомним, что в программе, предложенной для решения задачи 6.1 (П1)\
для хранения сведений об одном сотруднике была использована следующая
структура Man:
struct Man {
char name[l_name + 1]:
1nt birth_year;
float pay:
}:
Начнем с того, что преобразуем эту структуру в класс, так как мы предполагаем,
что наш новый тип будет обладать более сложным поведением, чем просто чтение
и запись его полей:
class Man {
char name[l_name + 1]:
1nt b1rth_year:
float pay;
}:
Замечательно. Это у нас здорово получилось! Все поля класса по умолчанию —
закрытые (private). Так что если клиентская функция ma1n() объявит объект Man
man, а потом попытается обратиться к какому-либо его полю, например: man.pay =
value, то компилятор быстро пресечет это безобразие, отказавшись компилировать
программу. Поэтому в состав класса надо добавить методы доступа к его полям.
Эти методы должны быть общедоступными, или открытыми (public).
Однако предварительно вглядимся внимательнее в определения полей. В решении
задачи 6.1 (П1) поле name объявлено как статический массив длиной l_name + 1.
Это не очень гибкое решение. Мы хотели бы, чтобы наш класс Man можно было
использовать в будущем в разных приложениях. Например, если предприятие
находится в России, то значение l_name = 30, по-видимому, всех устроит, если же
приложение создается для некой восточной страны, может потребоваться, скажем,
значение l_name = 200. Решение состоит в использовании динамического массива
символов с требуемой длиной. Поэтому заменим поле char named_name + 1]
на поле char* pName. Сразу возникает вопрос: кто и где будет выделять память
под этот массив? Вспомним один из принципов ООП: все объекты должны быть
самодостаточными, то есть полностью себя обслуживать.
Таким образом, в состав класса необходимо включить метод, который обеспечил
бы выделение памяти под указанный динамический массив при создании объекта
(перемершой типа Man). Метод, который автоматически вызывается при создании
экземпляра класса, называется конструктором. Компилятор безошибочно
находит этот метод среди прочих методов класса, поскольку его имя всегда совпадает
с именем класса.
Парным конструктору является другой метод, называемый деструктором, который
автоматически вызывается перед уничтожением объекта. Имя деструктора
Запись в скобках «П1» означает, что имеется в виду задача 6.1 из первой книги практикума.
