Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 102 103 104 [ 105 ] 106 107 108 ... 144


class io obj { полиморфный virtual io obj* clone();

Функция get obj () является самой важной в системе объектного ввода/вывода. Она читает данные из istream и создает из них объекты классов. Допустим, что данным, представляющим в потоке объект, предшествует строка, идентифицирующая его класс. Тогда get ob j (} должна считать эту строку и вызвать функцию, которая может создать и инициализировать объект нужного класса. Например:

typedef io obj* {*PF)(istreamb);

Map<String,PF> io map; отображение строк на функции создания

io obj get obj(istrearaS s) {

String str;

if (get word(s,str) == 0) прочитать в str начальное слово throw no class;

PF f = io map[str]; найти функцию по str if (f == 0) throw unknown class; функции не нашлось io .obj* p = f(s); сконструировать объект из потока if (debug) cout << typeid(*p).name() \n;

Отображение io map класса Map - это ассоциативный массив, который содержит пары, состоящие из строки имени и функции, способной сконструировать объект класса с этим именем. Тип Map в любо.м языке относится к числу наиболее полезных и эффективных структур данных. Одна из первых реализаций этой идеи принадлежит Эндрю Кенигу [Koenig, 1988], см. также [2nd, §8.8].

Обратите вннмание на использование typeid () для отладки. При данном проектировании это единственное место, где используется RTTI.

Мы могли бы, конечно, определить класс Shape обычным образо.м, наследуя классу io .obj, как того требует функция user ():

class Shape : public io ob.i ( ...

Ho было бы лучше (a во многих случаях и более реалистично) использовать уже имеющийся класс Shape, не изменяя иерархию:

class iocircle : public Circle, public io obj { public:

iocircle* cloneO замещает io obj::clone { return new iocircle(*this); }

iocircle(istream&); инициализует из входного потока



static iocircle* new circle(istream& s) {

return new iocircle(s);

...

Конструктор iocircle (istream&) инициализирует объект на основе данных, считываемых из потока istream. Функция new circle помещается в io map, чтобы сделать класс известным системе объектного ввода/вывода. Напри.мер:

io map[ iocircle ]=&iocircle::new circle;

Другие фигуры конструируются аналогично:

class iotriangle : public Triangle, public io,.obj { ...

Поскольку постоянно адаптировать новые типы к объектному вводу/выводу утомительно, можно воспользоваться шаблонами:

template<class Т>

class io : public Т, public io obj { public:

io* clone!) замещает io obj::clone { return new io(*this); }

io(istream&); инициализирует из входного потока

static io* new io(istreams s) {

return new io(s);

...

Тогда можно было бы определить iocircle следующим образом, typedef io<Circle> iocircle;

Но определить функцию io<Circle>: : io (istream&) все же пришлось бы явно, поскольку ей нужно знать о деталях Circle.

Столь простая система объектного ввода/вывода не может удовлетворить всем пожелания.м пользователя, но весь ее код умещается на одной странице, а основные механизмы мог>т naiiTn различные применс1{ня. В обычной ситуации такую технику можно использовать для вызова функции на основе строки, указанной пользователем.

14.2.8. Другие варианты

Механизм RTTI можно сравнить с луковицей. Снимая слой за слоем, вы все равно обнаруживаете полезные средства. Но если злоупотребить ими, то .можно горько пожалеть.



Главный принцип описанных выше механизмов RTTI заключается в том, чтобы максимально упростить программирование и минимизировать зависимость от реализации. Но RTTI следует применять как можно реже:

□ лучше всего вовсе не пользоваться информацией о типе во время исполнения, а всецело полагаться на статическую проверку (на этапе ко.мпиляции);

□ если это невозможно, следует использовать только динамические приведения типов. В таком случае нам даже не нужно знать точное имя типа объекта и включать относящиеся к RTTI заголовочные файлы;

□ когда недостаточно и этого, можно сравнивать значения, возвращаемые typeid (), для чего необходимо знать точное имя, по крайней мере, одного из типов. Предполагается, что рядово.му пользователю нет нужды знать что-нибудь еще о типах во время исполнения;

□ наконец, если абсолютно необходимо иметь о типе более детальную информацию - скажем, для реализации отладчика, систе.мы баз данных или какой-либо иной формы системы объектного ввода/вывода, - можно воспользоваться операциями над typeid.

Такое предоставление ряда средств, тесно связанных с динамическими свой-ства.ми класса, противоположно другому подходу: создать класс, описывающий стандартный взгляд на эти свойства, - метакласс. В С-ы- поощряется использование статической системы типов (более безопасной и эффективной), которая понятней пользователям и дает возможность оценить разные аспекты класса для получения детальной информации.

Рассматривалось несколько альтернатив такому луковичному подходу .

14.2.8.1. Метаобъекты

Луковичный объект отличается от принятых в языках Smalltalk и CLOS, хотя нечто подоб1юе несколько раз предлагалось и для С+-1-. В таких системах вместо type inf о применяются метаобъекты, способные во вре.мя исполнения принимать запросы на выполнение любой операции, допусти.мой над объектом в языке. По сути дела, механизм метаобъектов подразумевает натчие встроенного интерпретатора всего языка в исполняющей среде Представлялось, что подобный потенциальный способ обхода механизмов защиты опасен для эффективности языка и не стыкуется с базовыми принципами проектирования и документирования, основанными на статическом контроле типов.

Возражения против того, чтобы понятие метаобъектов легло в основу C+-I-, отнюдь не означают, что метаобъекты нельзя с пользой применить. Безусловно, можно, и концепция расширенной информации о типе поможет тем, кто действительно хотел бы предоставить данные средства на уровне библиотек. Но я не могу рекомендовать такое проектирование и реализацию для программирования типичных задач на С-ы- [2nd, §12].

14.2.8.2. Оператор опроса типа

Для многих пользователей оператор, отвечающий на вопрос принадлежит ли *рЬ классу D или производному от него? , кажется гораздо более понятным, чем



1 ... 102 103 104 [ 105 ] 106 107 108 ... 144

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