Программирование >>  Поддержка объектно-ориентированного программирования 

1 ... 110 111 112 [ 113 ] 114 115 116 ... 120


Функция has base() ищет базовые классы с помощью имеющегося в Type info списка базовых классов. Хранить информацию о том, является ли базовый класс частным или виртуальным, не нужно, поскольку все ошибки, связанные с ограничениями доступа или неоднозначностью, будут выявлены при трансляции.

class base iterator { short i; short alloc; const Type info* b; public:

const Type info* operator() (); void reset() { i = 0; }

base iterator(const Type info* bb, int direct=0); ~base iterator() { if (alloc) delete[] (Type info*)b; }

В следующем примере используется необязательный параметр для указания, следует ли рассматривать все базовые классы (direct==0) или только прямые базовые классы (direct==1).

base iterator::base iterator(const Type info* bb, int direct)

i = 0;

if (direct) { использование списка прям1х базовых классов b = bb;

alloc = 0; return;

создание списка прямых базовых классов: int n = число базовых b = new const Type info*[n+1]; занести базовые классы в b

alloc = 1; return;

const Type info* base iterator::operator() ()

const Type info* p = &b[i]; if (p) return p;

Теперь можно задать операции запросов о типе с помощью макроопределений:

#define static type info(T) T::info() #define ptr type info(p) ((p)->get info()) #define ref type info(r) ((r).get info()) #define ptr cast(T,p) \

(T::info()->can cast((p)->get info()) ? (T*)(p) : 0) #define ref cast(T,r) \

(T::info()->can cast((r).get info()) \

? 0 : throw Bad cast(T::info()->name()), (T&)(r))

Предполагается, что тип особой ситуации Bad cast (Ошибка приведения) описан так:

class Bad cast { const char* tn;

...

public:

Bad cast(const char* p) : tn(p) { } const char* cast to() { return tn; } ...



В разделе $$4.7 было сказано, что появление макроопределений служит сигналом возникших проблем. Здесь проблема в том, что только транслятор имеет непосредственный доступ к литеральным типам, а макроопределения скрывают специфику реализации. По сути для хранения информации для динамических запросов о типах предназначена таблица виртуальных функций. Если реализация непосредственно поддерживает динамическую идентификацию типа, то рассматриваемые операции можно реализовать более естественно, эффективно и элегантно. В частности, очень просто реализовать функцию ptr cast(), которая преобразует указатель на виртуальный базовый класс в указатель на его производные классы.

13.5.3 Как создать систему динамических запросов о типе

Здесь показано, как можно прямо реализовать динамические запросы о типе, когда в трансляторе таких возможностей нет. Это достаточно утомительная задача и можно пропустить этот раздел, так как в нем есть только детали конкретного решения.

Классы set и slist set из $$1 3.3 следует изменить так, чтобы с ними могли работать операции запросов о типе. Прежде всего, в базовый класс set нужно ввести функции-члены, которые используют операции запросов о типе:

class set { public:

static const Type info info obj; virtual typeid get info() const; static typeid info(); ...

При выполнении программы единственным представителем объекта типа set является set::info obj, который определяется так:

const Type info set::info obj( set ,0);

С учетом этого определения функции тривиальны:

typeid set::get info() const { return &info obj; } typeid set::info() { return &info obj; }

typeid slist set::get info() const { return &info obj; } typeid slist set::info() { return &info obj; }

Виртуальная функция get info() будет предоставлять операции ref type info() и ptr type info(), а статическая функция info() - операцию static type info().

При таком построении системы запросов о типе основная трудность на практике состоит в том, чтобы для каждого класса объект типа Type info и две функции, возвращающие указатель на этот объект, определялись только один раз.

Нужно несколько изменить класс slist set:

class slist set : public set, private slist {

...

public:

static const Type info info obj; virtual typeid get info() const; static typeid info(); ...

static const Type info* slist set b[]

= { &set::info obj, &slist::info obj, 0 }; const Type info slist set::info obj( slist set ,slist set b); typeid slist set::get info() const { return &info obj; } typeid slist set::info() { return &info obj; }



if (ref type info(s)==static type info(Circle)) { для этой фигуры ничего не надо

}else if (ref type info(s)==static type info(Triangle)) { вращение треугольника

else if (ref type info(s)==static type info(Square)) { вращение квадрата

...

Если для переключателя по типу поля мы используем динамическую информацию о типе, то тем самым нарушаем в программе принцип модульности и отрицаем сами цели объектно-ориентированного программирования. К тому же это решение чревато ошибками: если в качестве параметра функции будет передан объект производного от Circle класса, то она сработает неверно (действительно,

13.5.4 Расширенная динамическая информация о типе

В классе Type info содержится только минимум информации, необходимой для идентификации типа и безопасных операций приведения. Но поскольку в самом классе Type info есть функции-члены info() и get info(), можно построить производные от него классы, чтобы в динамике определять, какие объекты Type info возвращают эти функции. Таким образом, не меняя класса Type info, пользователь может получать больше информации о типе с помощью объектов, возвращаемых функциями dynamic type() и static type(). Во многих случаях дополнительная информация должна содержать таблицу членов объекта:

struct Member info { char* name; Type info* tp; int offset;

class Map info : public Type info { Member info** mi; public:

static const Type info info obj; virtual typeid get info() const; static typeid info(); функции доступа

Класс Type info вполне подходит для стандартной библиотеки. Это базовый класс с минимумом необходимой информации, из которого можно получать производные классы, предоставляющие больше информации. Эти производные классы могут определять или сами пользователи, или какие-то служебные программы, работающие с текстом на С++, или сами трансляторы языка.

13.5.5 Правильное и неправильное использование динамической

информации о типе

Динамическая информация о типе может использоваться во многих ситуациях, в том числе для: объектного ввода-вывода, объектно-ориентированных баз данных, отладки. В тоже время велика вероятность ошибочного использования такой информации. Известно,что в языке Симула использование таких средств, как правило, приводит к ошибкам. Поэтому эти средства не были включены в С++. Слишком велик соблазн воспользоваться динамической информацией о типе, тогда как правильнее вызвать виртуальную функцию. Рассмотрим в качестве примера класс Shape из $$1.2.5. Функцию rotate можно было задать так:

void rotate(const Shape& s)

неправильное использование динамической информации о типе



1 ... 110 111 112 [ 113 ] 114 115 116 ... 120

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