Программирование >>  Инициализация объектов класса, структура 

1 ... 280 281 282 [ 283 ] 284 285 286 ... 395


полиморфизма нет

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) Геометрические примитивы (прямоугольник, круг, сфера, конус и т. д.)



1 ... 280 281 282 [ 283 ] 284 285 286 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика