
- •1. Абстрактные типы данных
- •Пример 1
- •1.4. Разработка объектов
- •1.4.1. Объекты и композиция
- •Пример 3
- •1.4.3. Объекты и наследование
- •1.4.4. Наследование в программировании
- •1.4.5. Упорядоченные списки и наследование
- •1.4.6. Повторное использование кода
- •1.4.7. Спецификации класса SeqList и OrderedList
- •1.5. Приложения с наследованием классов
- •1.6. Разработка объектно-ориентированных программ
- •1.6.1. Анализ задачи/определение программы
- •1.6.2. Разработка
- •1.6.3. Кодирование
- •1.6.4. Тестирование
- •1.6.5. Иллюстрация программной разработки: Dice график
- •Замечание
- •Программа 2. Диаграмма бросания костей
- •1.7. Тестирование и сопровождение программы
- •1.7.1. Объектное тестирование
- •1.7.2. Тестирование управляющего модуля
- •1.7.3. Программное сопровождение и документирование
- •1.9. Абстрактные базовые классы и полиморфизм
- •1.9.1. Полиморфизм и динамическое связывание
- •2.1. Пользовательский тип — класс
- •2.1.1. Объявление класса
- •Пример 1.
- •2.1.2. Конструктор
- •2.1.3. Объявление объекта
- •2.1.4. Реализация класса
- •2.1.5. Реализация конструктора
- •2.1.6. Создание объектов
- •Пример 2.
- •2.2. Примеры классов
- •2.2.1. Класс Temperature
- •2.2.2. Реализация класса Temperature
- •2.2.3. Класс случайных чисел
- •Пример 3.
- •2.2.4. Реализация класса RandomNumber
- •2.3. Объекты и передача информации
- •2.3.1. Объект как возвращаемое значение
- •2.3.2. Объект как параметр функции
- •2.4. Массивы объектов
- •2.4.1. Конструктор умолчания
- •2.5. Множественные конструкторы
- •2.5.1. Реализация класса Date
- •2.6. Практическое применение: Треугольные матрицы
- •2.6.1. Свойства верхней треугольной матрицы
- •2.6.2. Хранение треугольной матрицы
- •Пример 4.
- •Пример 5.
- •2.6.3. Класс TriMat
- •2.6.5. Реализация класса TriMat
1.9. Абстрактные базовые классы и полиморфизм
Наследование классов объединяется с абстрактными базовыми классами (abstract base classes) для создания важного инструмента разработки структуры данных. Эти абстрактные базовые классы определяют открытый интерфейс класса, независимый от внутренней реализации данных класса и операций. Открытый интерфейс класса определяет методы доступа к данным. Клиент хочет, чтобы открытый интерфейс оставался постоянным, несмотря на изменения во внутренней реализации. Объектно-ориентированные языки подходят к этой проблеме, используя абстрактный базовый класс, который объявляет имена и параметры для каждого из public-методов. Абстрактный базовый класс предоставляет ограниченные детали реализации и сосредотачивает внимание на объявлении public-методов. Это объявление форсирует реализацию в производном классе. Абстрактный базовый класс C++ объявляет некоторые методы как чистые виртуальные функции (pure virtual functions). Следующее объявление определяет абстрактный базовый класс List, который задает операции списка. Слово "virtual" и присвоение нуля операции определяют чистую виртуальную функцию.
template <class T>
class List
{
protected:
// число элементов в списке.
// обновляется производным классом
int size size;
public:
// конструктор
List(void);
// методы доступа
virtual int ListSize(void) const;
virtual int ListEmpty(void) const;
virtual int Find(T& item) = 0;
// методы модификации списка
virtual void Insert(const T& item) = 0;
virtual void Delete(const T& item) = 0;
virtual void ClearList(void) = 0;
};
Этот абстрактный базовый класс предназначен для описания очень общих списков. Он используется как база для серии классов наборов (структур списков) в последующих главах. Использование абстрактного класса в качестве базы требует, чтобы наборы реализовывали общие методы класса List. Для иллюстрации этого процесса класс SeqList снова рассматривается в главе 12, где он порождается от List.
1.9.1. Полиморфизм и динамическое связывание
Концепция наследования поддерживается в языке C++ рядом мощных конструкций. Мы уже рассмотрели чистые виртуальные функции в абстрактном базовом классе. Общая концепция виртуальных функций поддерживает наследование в том, что позволяет двум или более объектам в иерархии наследования иметь операции с одним и тем же объявлением, выполняющие различные задачи. Это объектно-ориентированное свойство, называемое полиморфизм (polymorhism), позволяет объектам из множества классов отвечать на одно и то же сообщение. Получатель этого сообщения определяется динамически во время выполнения. Например, системный администратор может использовать полиморфизм для обработки резервных файлов в многосистемной среде. Предположим, что администратор имеет подсистему с магнитной лентой 1/2 дюйма и компактный магнитофон с лентой 1/4 дюйма. Классы HalfTape и Quarter-Tape являются производными от общего класса Таре и управляют соответствующими лентопротяжными устройствами. Класс Таре имеет виртуальную операцию Backup, содержащую действия, общие для всех лентопротяжных устройств. Производные классы имеют (виртуальную) операцию Backup, использующую специфическую внутреннюю информацию о лентопротяжных механизмах. Когда администратор дает указание выполнить системное резервное копирование, каждый лентопротяжный механизм принимает сообщение Backup и выполняет особую операцию, определенную для его аппаратных средств. Объект типа HalfTape выполняет резервное копирование на 1/2-дюймовую ленту, а объект типа QuarterTape – на 1/4-дюймовую ленту.
Концепция полиморфизма является фундаментальной для объектно-ориентированного программирования. Профессионалы часто говорят об объектно-ориентированном программировании как о наследовании с полиморфизмом времени исполнения. C++ поддерживает эту конструкцию, используя динамическое связывание (dynamic binding) и виртуальные функции-члены (virtual member functions). Эти понятия описываются в главе 12. Сейчас же мы концентрируем внимание на этих понятиях, не давая технической информации о языковой реализации.
House
Paint
WoodFrame
Paint
Stucco
Paint
VinylSided
Paint
Динамическое связывание позволяет многим различным объектам в системе отвечать на одно и то же сообщение. Каждый объект отвечает на это сообщение определенным для его типа способом. Рассмотрим работу профессионального маляра, когда он (или она) выполняет малярную работу с различными типами домов. Определенные общие задачи должны быть выполнены при покраске дома. Допустим, что они описываются в классе House. Кроме общих задач требуются особые методы работы для различных типов домов. Покраска деревянного дома отличается от покраски дома с наружной штукатуркой или дома с виниловой облицовкой стен и так далее. В контексте объектно-ориентированного программирования особые малярные задачи для каждого вида дома задаются в производном классе, который наследует базовый класс House. Допустим, что каждый производный класс имеет операцию Paint. Класс House имеет операцию Paint, которая задается как виртуальная функция. Предположим, что Big Woody – это объект типа Wood-Frame. Мы можем указать Big Woody покрасить дом, вызывая явно операцию Paint. Это называется статическим связыванием (static binding).
BigWoody. Paint ( );// static binding
Допустим, однако, что подрядчик имеет список адресов домов, которые нуждаются в покраске, и что он передает сообщение своей команде маляров пойти по адресам в списке и покрасить эти дома. В данном случае каждое сообщение привязано не к определенному дому, а скорее – к адресу дома-объекта в списке. Команда маляров приходит к дому и выбирает правильную малярную операцию Paint, после того, как она увидит тип дома. Этот процесс известен как динамическое связывание (dynamic binding).
(House at address 414).Paint ( ); // dynamic binding
Процесс вызывает операцию Paint, соответствующую дому по данному адресу. Если дом по адресу 414 является деревянным, то выполняется операция Paint( ) из класса WoodFrame.
При использовании структур наследования в C++ операции, которые динамически связываются с их объектом, объявляются как виртуальные функции-члены (virtual member functions). Генерируется код для создания таблицы, указывающей местоположения виртуальных функций какого-либо объекта и устанавливается связь между объектом и этой таблицей. Во время выполнения, когда на положение объекта осуществляется ссылка, система использует это положение для получения доступа к таблице и выполнения правильной функции.
Понятие полиморфизма является фундаментальным в объектно-ориентированном программировании. Мы используем его с более совершенными структурами данных.
2. БАЗОВЫЕ КОНЦЕПЦИИ КЛАССОВ В С++
Выше были даны абстрактные типы данных (ADT) и их представление в качестве классов C++. Это введение описывает структуру класса, которая обеспечивает инкапсуляцию данных и скрытие информации. В этой главе содержится более полное описание базовых концепций класса. Здесь рассматриваются разработка и использование конструкторов класса, реализация методов класса и использование классов с другими структурами данных. Для обеспечения хорошего понимания классов читателем приводится широкий диапазон примеров, которые используются в законченных программах. Выбранные соответствующим образом ADT иллюстрируют связь между абстрактной структурой и объявлением класса.