|
Программирование >> Структурное программирование
10.5. Полиморфизм C-I-I- включает такое свойство, как полиморфизм - возможность для объектов разных классов, связанных с помощью наследования, реагировать различным образом при обращении к одной и той же функции-элементу. Если, например, класс Rectangle (прямоугольник) является производным от класса Quadrilateral (четырехугольник), то тогда объект класса Rectangle является более конкретизированным вариантом объекта класса Quadrilateral. Операция (такая, как вычисление периметра или площади), которая может быть выполнена для объекта класса Quadrilateral, может быть также выполнена и для объекта класса Rectangle. Полиморфизм реализуется посредством виртуальных функций. Если при использовании виртуальной функции запрос осуществляется с помощью указателя базового класса (или ссылки), то C-h-l- выбирает правильную переопределенную функцию в соответствующем производном классе, связанном с данным объектом. Иногда функция-элемент определена в базовом классе не как виртуальная, но переопределена в производном классе. Если такая функция-элемент вызывается через указатель базового класса, то используются версия базового класса. Если же эта функция-элемент вызывается через указатель производного класса, то используется версия производного класса. Это не полиморфное поведение. Рассмотрим следующий пример, в котором использованы базовый класс Employee (служащие) и производный класс HourlyWorker (почасовики), приведенные на рис. 9.5. Employee е, *ePtr = &е; HourlyWorker h, *hPtr = &h; ePtr ->print; вызов функции-элемента print базового класса hPtr->print; вызов функции-элемента print производного класса Наш базовый класс Employee и производный класс HourlyWorker имеют свои собственные функции print, которые определены в этих классах. Поскольку эти функции не объявлены виртуальными и имеют одинаковую сигнатуру, то вызов функции print через указатель класса Employee приводит к вызову функции print из базового класса Employee, т.е. выполняется операция Employee::print( ), а вызов функции print через указатель класса HourlyWorker приводит к вызову функции print из производного класса HourlyWorker. Функция print базового класса также является элементом производного класса, но при вызове функции print для объекта производного класса вариант функции базового класса должен быть вызван явным образом, как показано ниже : hPtr->Employee::print( ) ; Эта запись явным образом определяет, что должна быть вызвана функция print базового класса. зовые классы TwoDimensionalObject и ThreeDimensionalObject. При переходе еще на один уровень ниже мы смогли бы определить конкретные классы для таких двумерных форм, как круги и квадраты, а также определить конкретные классы для таких трехмерных форм, как сфера и куб. Благодаря применению виртуальных функций и полиморфизму вызов функции-элемента может привести к различным действиям, которые зависят от типа вызываемого объекта (мы увидим впоследствии, что это требует незначительного количества дополнительных затрат). Подобное полиморфное поведение предоставляет программисту огромные возможности. В нескольких следующих разделах мы увидим примеры, которые демонстрируют, каким мощным средством являются полиморфизм и виртуальные функции. Замечание по технике программирования 10.6 Благодаря виртуальным функциям и полиморфизму программна может управлять общими свойствами объектов, предоставляя возможность программной среде во время выполнения программы самой заботиться о специфике объектов. Программист может управлять широким спектром объектов, даже не зная об их типах, причем управление будет автоматически учитывать специфику этих объектов. Замечание по технике программирования 10.7 Полиморфизм способствует расширяемости: программное обеспечение, использующее полиморфный механизм, пишется независимо от типов объектов, которым отправляются сообщения. Таким образом, новые типы объектов, которые должны реагировать на соответствующие сообщения, могут включаться в такую систему без модификации ее основы. За исключением кода пользователя, который создает новые объекты, программа не потребует перекомпиляции. Замечание по технике программирования 10.8 Абстрактный класс определяет интерфейс для разных типов элементов иерархии классов. Абстрактный класс включает чистые виртуальные функции, которые будут определены в производных классах. Все функции в иерархии могут применять один и тот же интерс)ейс, используя полиморфизм. Хотя мы не можем создавать объекты абстрактного базового класса, мы можем объявить указатели на абстрактный базовый класс. Эти указатели могут быть затем использованы, чтобы предоставить возможность для полиморфного оперирования объектами производных конкретных классов. Рассмотрим применение полиморфизма и виртуальных функций. Экранному администратору необходимо отображать множество объектов, включая новые типы объектов, которые будут включаться в систему даже после того, как будет написана сама программа экранного администратора. Системе может потребоваться отображать разные формы (базовым классом для них является класс Shape), такие, как квадраты, окружности, треугольники, прямоугольники и т.п. Каждый из этих классов форм является производным от базового класса Shape. Экранный администратор использует указатели базового класса (указатели на Shape) для управления всеми отображаемыми на экране объектами. Чтобы нарисовать объект (безотносительно уровня, на котором находится объект в иерархии наследования), экранный администратор использует указатель базового класса на объект и просто посылает сообщение объекту: нарисовать . Функция draw объявляется чистой виртуальной функцией в базовом классе Shape и должна быть переопределена в каждом из производных классов. Каждый объект базового класса Shape знает как себя нарисовать . Экранному администратору не надо заботиться 10.6. Учебный пример : система расчета заработной платы Давайте используем виртуальные функции и полиморфизм, чтобы выполнить расчет заработной платы, в котором учитывается тип служащего (см. рис. 10.1). Воспользуемся базовым классом Employee. Производными классами от базового класса Employee являются: класс Boss - служащим начисляется еженедельный фиксированный оклад независимо от числа проработанных часов; класс ComissionWorker - служащим начисляется базовая заработная плата плюс комиссионный процент от продаж; класс Pieceworker - служащим начисляется сдельная плата по количеству изготовленных изделий; класс HourlyWorker - служащим начисляется почасовая о том, какого типа каждый объект и вообще имел ли дело когда-нибудь экранный администратор с объектами такого типа; просто экранный администратор приказывает каждому объекту изобразить себя на экране. Полиморфизм особенно эффективен при реализации многоуровневых систем программного обеспечения. В операционных системах, например, каждый тип физического устройства может работать совершенно отлично от других. Несмотря на это, команды чтения данных с таких физических устройств read и команды записи данных на физические устройства write могут иметь определенное единообразие. Сообщение write, посланное объекту драйверу устройства, интерпретируется специальным образом в зависимости от используемого драйвера и от того, каким образом этот драйвер управляет устройствами конкретного типа. Тем не менее, этот вызов write сам по себе действительно не отличается от вызовов write любого другого устройства в системе; вызов просто перемещает некоторое число байтов из памяти в конкретное устройство. Объектно-ориентированные операционные системы могут использовать абстрактные базовые классы для того, чтобы реализовать интерфейс, пригодный для драйверов всех устройств. Затем с помощью наследования этих абстрактных базовых классов образуются производные классы, которые работают одинаковым образом. Указанные возможности (т.е. открытый интерфейс), предоставленные драйверам устройств, обеспечиваются чистыми виртуальными функциями абстрактных базовых классов. Реализации этих виртуальных функций обеспечиваются в производных классах и соответствуют конкретным типам драйверов устройств. В главе 7 мы ввели понятие итераторов. Обыкновенно определяют класс итераторов, который обеспечивает обход всех объектов набора. Если, например, вы хотите напечатать перечень объектов в связном списке, то объект итератор может быть реализован таким образом, что он будет возвращать следующий элемент связного списка при каждом вызове этого итератора. Итераторы обычно применяются в полиморфном программировании для обхода в связном списке объектов различных иерархических уровней. Все указатели в таком списке могут быть указателями базового класса (см. главу 15 Структуры данных , в которой рассматриваются связные списки). Список объектов класса TwoDimensionalShape может включать объекты из классов Square, Circle, Triangle и т.д. При использовании полиморфизма отправка сообщения нарисовать каждому объекту списка обеспечивала бы изображение на экране правильной картинки.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |