На этом шаге мы рассмотрим общие положения, связанные с динамической идентификацией типов.
Недавнее добавление в проект стандарта языка С++ механизма динамической идентификации типов (RTTI - Run-Time Type Identification) расширяет язык набором средств, позволяющих идентифицировать конкретные типы объектов во время выполнения программы, даже если известны только указатель или только ссылка на интересующий вас объект. (Отметим, что для использования средств динамического определения типов к программе необходимо подключить файл typeinfо.h.)
Механизм динамического определения (идентификации) типов позволяет проверить, является ли некоторый объект объектом заданного типа, а также сравнивать типы двух данных объектов. Для этого используется операция typeid, которая определяет тип аргумента и возвращает ссылку на объект типа const typeinfо, описывающий этот тип. В качестве аргумента typeid можно также использовать и имя некоторого типа. В этом случае typeid вернет ссылку на объект const typeinfo этого типа. Класс typeinfo содержит операции-функции operator== и operator!=, которые используются для сравнении типов объектов. Класс typeinfo также содержит компонентную функцию name(), возвращающую указатель на строку, содержащую ими типа аргумента.
Операция typeid имеет две формы:
typeid (выражение) typeid (имя_типа)
Эта операция используется для динамического получения информации о типах данных. typeid возвращает ссылку на объект типа const typeinfo. Возвращаемый объект представляет тип операнда оператора typeid.
При динамической идентификации типов важным свойством типа является его полиморфность. Напомним, что понятие полиморфности введено для обозначения классов, имеющих по крайней мере одну виртуальную или чисто виртуальную функцию.
Если операнд операции typeid есть разыменованный указатель или ссылка на полиморфный тип, typeid возвращает динамический тип объекта, получаемого по указателю или ссылке на него. Если операнд неполиморфный, typeid вернет объект, представляемый статическим типом. При этом вы можете использовать операцию typeid как с основными типами данных, так и с производными.
Если операнд операции typeid суть разыменованный нулевой указатель, порождается исключение Bad_typeid.
Класс typeinfo описан в файле typeinfo.h (если не считать некоторых опущенных нами модификаторов, не влияющих на существо дела) следующим образом:
class __rtti typeinfo { public: tpid * tpp; private: typeinfo(const typeinfo &); typeinfo & operator=(const typeinfo &); public: virtual ~typeinfo(); int operator==(const typeinfo &) const; int operator!=(const typeinfo &) const; int before(const typeinfo &) const; const char * name() const; };
Общедоступная компонентная функция name() возвращает указатель на строку, определяющую тип операнда typeid. Конкретная длина возвращаемой строки может изменяться при каждом новом вызове функции.
Компонентная функция before() производит лексикографическое сравнение названий (имен) типов двух заданных объектов. Для этого необходимо использовать следующую конструкцию:
typeid(T1).before(typeid(T2));
Если имя типа Т1 "предшествует" имени типа Т2, то функция возвращает 1, в противном случае возвращается 0. Рассмотрим следующий вариант программы:
//EXC15_1.СРР - идентификация и сравнение типов объектов. #include <typeinfo.h> #include <iostream.h> void main() { char szString[10]; float floatVar; cout << typeid(szString).name() << ", " << typeid(floatVar).name(); cout << endl << typeid(szString).before(typeid(floatVar)); }
Результат выполнения программы:
char *, float 1
В первой строке результата в текстовом виде напечатаны названия типов переменных szString и f loatVar, а во второй строке - результат выполнения функции before(). Он равен 1. Это означает, что строка "char *" лексикографически предшествует строке "float", что соответствует латинскому алфавиту.
Операции-функции operator==() и operator!=() обеспечивают сравнение двух типов данных.
Пусть szString и f loatVar описаны так, как в предыдущем примере, тогда
... typeid(szString)==typeid(f loatVar) ... // Условие не выполнено. ... typeid(szString)!=typeid(floatVar)... // Условие выполнено.
На следующем шаге мы продолжим знакомство с динамической идентификацией типов.