|
Программирование >> Инициализация объектов класса, структура
полиморфизма нет int *pi; нет поддержанного языком полиморфизма void *pvi; pery может адресовать объект бого производного от Query класса обязательно приводит к полиморфизму. Рассмотрим такие объявления: Query *pquery; В C++ полиморфизм существует только в пределах отдельных иерархий классов. Указатели типа void* можно назвать полиморфными, но в языке их поддержка не предусмотрена. Такими указателями программист должен управлять самостоятельно, с помощью явных приведений типов и той или иной формы дискриминанта, показывающего, объект какого типа в данный момент адресуется. (Можно сказать, что это второсортные полиморфные объекты.) Язык C++ обеспечивает поддержку полиморфизма следующими способами: путем неявного преобразования указателя или ссылки на производный класс к указателю или ссылке на открытый базовый: Query *pery = new NameQuery( Class ); через механизм виртуальных функций: pquery->eval(); с помощью операторов dynamic cast и typeid (они подробно обсуждаются в if ( NameQuery *pnq = разделе 19.1): dynamic cast< NameQuery* >( pquery )) ... Проблему представления запроса мы решим, определив каждый операнд в классах AndQuery, NotQuery и OrQuery как указатель на тип Query*. Например: В объектно-ориентированной парадигме программист манипулирует неизвестным экземпляром, принадлежащим к одному из ограниченного, но потенциально бесконечного множества различных типов. (Ограничено оно иерархией наследования. Теоретически, однако, ни на глубину, ни на ширину такой иерархии не накладывается никаких ограничений.) В C++ это достигается путем манипулирования объектами исключительно через указатели и ссылки на базовый класс. В объектной (не объектно-ориентированной) парадигме программист работает с экземпляром фиксированного типа, который полностью определен на этапе компиляции. Хотя для полиморфной манипуляции объектом требуется, чтобы доступ к нему осуществлялся с помощью указателя или ссылки, сам по себе факт их использования не class AndQuery { public: ... private: Query * lop; Query * rop; Теперь оба операнда могут адресовать объект любого класса, производного от абстрактного базового класса Query, без учета того, определен он уже сейчас или появится в будущем. Благодаря механизму виртуальных функций, вычисление операнда, происходящее во время выполнения программы, не зависит от фактического типа: rop->eval(); На рис. 17.1 показана иерархия наследования, состо ящая из абстрактного класса Query четырех производных от него классов. Как этот рисунок на C++? дПОиегу OcQuery транслируется в код программы OtQuery Рис. 17.1. Иерархия классов Query В разделе 2.4 м1 рассматривали реализацию иерархии классов IntArray. Синтаксическая структура определения иерархии, изображенной на рис. 17.1, class Query { ... }; class AndQuery : public Query class OrQuery : public Query class NotQuery : public Query аналогична: class NameQuery : public Query { Наследование задается с помощью списка базовых классов. В случае одиночного наследования этот список имеет вид: : уровень-доступа базов-класс где уровень-доступа - это одно из ключевых слов public, protected, private (см1сл защищенного и закрытого наследования мы обсудим в разделе 18.3), а базов1й-класс -имя ранее определенного класса. Например, Query является открытым базовым классом для любого из четырех классов запросов. Класс, встречающийся в списке базовых, должен быть предварительно определен. Следующего опережающего объявления Query недостаточно для того, чтобы он мог выступать в роли базового: ошибка: Query должен быть определен class Query; class NameQuery : piblic Query { ... }; Опережающее объявление производного класса должно включать только его имя, но не список базовых классов. Поэтому следующее опережающее объявление класса NameQuery ошибка: опережающее объявление не должно включать списка базовых классов приводит к ошибке компиляции: class NameQuery : public Query; опережающее объявление как производного, так и обычного класса содержит только имя класса class Query; Правильный вариант в данном случае выглядит так: class NameQuery; Главное различие между базовыми классами Query и IntArray (см. раздел 2.4) состоит в том, что Query не представляет никакого реального объекта в нашем приложении. Пользователи класса IntArray вполне могут определять и использовать объекты этого типа непосредственно. Что же касается Query, то разрешается определять лишь указатели и ссылки на него, используя их для косвенного манипулирования объектами производных классов. О Query говорят, что это абстрактный базовый класс. В противоположность этому IntArray является конкретньм базовым классом. Преобладающей формой в объектно-ориентированном проектировании является определение абстрактного базового класса типа Query и одиночное открытое наследование ему. Упражнение 17.1 Библиотека может выдавать на руки предметы, для каждого из которых определены книга аудио-книга аудиокассета детская кукла видеоигра для приставки SEGA видеоигра для приставки SONY видеокассета книга с подневной оплатой видеоигра для приставки SONY специальные правила выдачи и возврата. Организуйте их в иерархию наследования: книга на компакт-диске видеоигра для приставки Nintendo Упражнение 17.2 Выберите или придумайте собственную абстракцию, содержащую семейство типов. Организуйте типы в иерархию наследования: (a) Форматы графических файлов (gif, tiff, jpeg, bmp и т.д.) (b) Геометрические примитивы (прямоугольник, круг, сфера, конус и т. д.)
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |