Бьерн Страуструп. Язык программирования С++ Второе дополненное издание



Pdf көрінісі
бет244/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   240   241   242   243   244   245   246   247   ...   256
Байланысты:
Бьерн Страуструп. Язык программирования С . М Бином, 2011

13.5.2 Класс Type_info 
В классе Type_info есть минимальный объем информации для реализации операции ptr_cast(); его 
можно определить следующим образом: 
class Type_info { 
const char* n; 
// 
имя 
const Type_info** b; 
// список базовых классов 
public: 
Type_info(const char* name, const Type_info* base[]); 
const char* name() const; 
Base_iterator bases(int direct=0) const; 
int same(const Type_info* p) const; 
int has_base(const Type_info*, int direct=0) const; 
int can_cast(const Type_info* p) const; 
static const Type_info info_obj; 
virtual typeid get_info() const; 
static 
typeid 
info(); 
}; 
Две последние функции должны быть определены в каждом производном от Type_info классе. 
Пользователь не должен заботиться о структуре объекта Type_info, и она приведена здесь только для 
полноты изложения. Строка, содержащая имя типа, введена для того, чтобы дать возможность поиска 
информации в таблицах имен, например, в таблице отладчика. С помощью нее а также информации из 
объекта Type_info можно выдавать более осмысленные диагностические сообщения. Кроме того, если 
возникнет потребность иметь несколько объектов типа Type_info, то имя может служить уникальным 
ключом этих объектов. 
const char* Type_info::name() const 

return 
n; 

int Type_info::same(const Type_info* p) const 

return this==p || strcmp(n,p->n)==0; 

int Type_info::can_cast(const Type_info* p) const 

return same(p) || p->has_base(this); 

Доступ к информации о базовых классах обеспечивается функциями bases() и has_base(). Функция 
bases() возвращает итератор, который порождает указатели на базовые классы объектов Type_info, а с 
помощью функции has_base() можно определить является ли заданный класс базовым для другого 
класса. Эти функции имеют необязательный параметр direct, который показывает, следует ли 
рассматривать все базовые классы (direct=0), или только прямые базовые классы (direct=1). Наконец, 
как описано ниже, с помощью функций get_info() и info() можно получить динамическую информацию о 
типе для самого класса Type_info. 
Здесь средство динамических запросов о типе сознательно реализуется с помощью совсем простых 
классов. Так можно избежать привязки к определенной библиотеке. Реализация в расчете на 
конкретную библиотеку может быть иной. Можно, как всегда, посоветовать пользователям избегать 
излишней зависимости от деталей реализации. 


Бьерн Страуструп.
Язык программирования С++ 
 
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) { // использование списка прямых базовых классов 


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


Достарыңызбен бөлісу:
1   ...   240   241   242   243   244   245   246   247   ...   256




©emirsaba.org 2024
әкімшілігінің қараңыз

    Басты бет