Бьерн Страуструп.
Язык программирования С++
348
Функция 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) { // использование списка прямых базовых классов
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) i++;
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; }
// ...
Бьерн Страуструп.
Язык программирования С++
349
};
В разделе $$4.7 было сказано, что появление макроопределений служит сигналом возникших проблем.
Здесь проблема в том, что только транслятор имеет непосредственный доступ к литеральным типам, а
макроопределения скрывают специфику реализации. По сути для хранения информации для
динамических запросов о типах предназначена таблица виртуальных функций. Если реализация
непосредственно поддерживает динамическую идентификацию типа, то
рассматриваемые операции
можно реализовать более естественно, эффективно и элегантно. В
частности, очень просто
реализовать функцию ptr_cast(), которая преобразует указатель на
виртуальный базовый класс в
указатель на его производные классы.
Достарыңызбен бөлісу: