Type info
Класс type_info объявлен следующим образом:
class _TIDIST _rtti type_info {
public:
tpid * tpp;
private:
cdecl type_info(const type info FAR &);
type info & cdecl operator=(const type_info _FAR &);
public:
virtual _cdecl ~type_info() ;
bool cdecl operator==(const type info FAR &) const;
bool cdecl operator!=(const type info FAR &) const;
bool _cdecl before(const type_info _FAR &) const;
const char _FAR *_cdecl name() const;
protected:
cdecl type_info(tpid * tpp) { tpp = tpp; } };
Ключевое слово _rtti перед именем класса гарантирует, что информация о типе для него будет генерироваться вне зависимости от состояния флажка Enable RTTI на странице C++ диалога Project Options (ему соответствует ключ компилятора -rt).
Открытые элементы класса представлены операциями сравнения на равенство и неравенство, а также функциями name () и before (). Первая возвращает указатель на символьную строку с именем типа. Вторая возвращает true, если класс ее объекта является базовым по отношению к классу аргумента.
Вот пример с использованием операции typeid и класса type_info:
Листинг 13.1. Операция typeid
//////////////////////////////////////////////////////
// Typeinfo.срр: Операция typeid.
//
#include <typeinfo.h>
#include <iostream.h>
#include <string.h>
#pragma hdrstop
#include <condefs.h>
class Base { // Базовый класс.
public:
virtual ~Base (){} };
class Derived: public Base { // Производный класс.
char *str;
public:
Derived(const char *s) {
str = new char[strien(s)+1];
strcpy(str, s);
}
~Derived() { delete [] str;}
const char *Get() ( return str;}};
int main() {
Derived d("Derived class' string.");
Base &bRef = d; // Базовая ссылка на производный объект.
cout << "Typeinfo of bRef: " << typeid(bRef).name() << end1;
if (typeid(bRef) == typeid(Derived))
cout << "Contents of bRef: "<< ((Derived 6)bRef).Get() << endl;
else
cout << "Cannot cast safely bRef to Derived." << endl;
return 0;
Здесь демонстрируется операция typeid, сравнение типов и функция name () класса type_inf о. Программа выводит:
Typeinfo of bRef: Derived
Contents of bRef: Derived class' string.
Сравнение типов объекта bRef и Derived показывает, что они совпадают, и программа приводит ссылку к производному типу. Если закомментировать виртуальный деструктор класса Base, он станет неполиморфным, и typeid уже не сможет определить тип объекта, на который в действительности ссылается bRef:
Typeinfo of bRef: Base
Cannot cast safely bRef to Derived.
Эта программа является примером того, как не следует поступать. Идентифицировать класс, затем привести ссылку к нужному типу — это попытка поставить RTTI на место виртуального механизма. Гораздо проще сделать функцию Get() виртуальной:
class Base { public:
virtual ~Base () { }
virtual const char *Get() { throw MyExcpt; } };
try {
cout << "Contents of bRef: " << bRef.Get() << endl;
} catch(MyExcept) {
}
При недопустимом типе объекта выбрасывается исключение (возможны и другие решения).
RTTI следует применять только в тех случаях, когда тип объекта не известен во время компиляции и нецелесообразно применение других средств C++ вроде позднего связывания.