В главе 9 при обсуждении виртуальных методов мы уже упоминали механизм RTTI, с помощью которого можно определить тип объекта во время выполнения; имея только указатель на него. Механизм динамической идентификации типа состоит из трех составляющих:
• оператора динамического преобразования типа dynamic_cast<> (см. п. п. 5.2.7
в [1]);
• оператора идентификации точного типа объекта typeidO (см. п. п. 5.2.8 в [1]);
• класса type_info (см. п. п. 18.5.1 в [1]);
Оператор dynamic__cast<> допускается применять к указателям только на полиморфные классы (содержащие хотя бы одну виртуальную функцию). Вообще-то любой класс легко сделать полиморфным, определив для него виртуальный деструктор. Оператор имеет следующий формат:
dynamic_cast<TMn *>(указатель)
Результатом является преобразованный указатель. Если преобразование указателя к нужному типу выполнить не удается, оператор возвращает нулевой указатель. Следовательно, результат преобразования нужно всегда проверять.
Преобразования допускаются только между «родственниками», то есть классами, входящими в одну иерархию наследования (тип указателя в круглых скобках должен быть родственным типу в угловых скобках). Преобразование может быть:
• повышающим — от производного класса к базовому;
• понижающим — от базового класса к производному;
• перекрестным — от одного производного класса к другому.
Как мы знаем, повышающее преобразование выполняется обычно по умолчанию посредством подстановки (см. главу 8). Тем не менее можно его выполнить и явно. Понижающее и перекрестное преобразования выполняются только с помощью оператора dynamic_cast<>.
Оператор dynamic_cast<> можно применять и к ссылкам. Формат оператора в этом случае такой:
dynamic_cast<THn &>(ссылка)
Все условия относительно «родственности» полиморфных классов должны выполняться и в этом случае, однако обработка аварийного случая происходит по-другому. Так как нулевых ссылок не бывает, при невозможности преобразования ссылки генерируется исключение bad_cast (см. п. п. 18.5.2 в [1]).
Если оператор dynamic_cast<> выполняет преобразование одного типа в другой, то оператор typeidO позволяет выяснить фактический тип класса. Для использования этого оператора необходимо включить в программу заголовок
#include<typeinfo>
В этом классе представлен класс type_info, который возвращается в качестве результата оператором typeidO. В стандарте (см. п. п. 18.5.1 в [1]) класс type_ i nf о определен так, как показано в листинге 10.6.
Как видите, объекты типа type_info невозможно ни создать, ни скопировать — конструкторы и операция присваивания закрыты. Объекты типа type__info можно сравнивать между собой — и это основные операции, которые используются совместно с оператором typeidO; можно получить имя типа с помощью метода name О. Как написано в [2], метод before () «позволяет сортировать информацию о типе type_info. Нет никакой связи между отношениями упорядочения, определяемыми beforeO, и отношениями наследования».
Оператор typeidO имеет две синтаксически одинаковые формы — разница заключается в аргументе:
typei d(выражение) typeid(MMfl_Tnna)
В качестве выражений наиболее часто применяются указатели. Таким образом, оператор typei d () позволяет определить точный тип объекта, на который указывает указатель. Если указатель нулевой, то возбуждается исключение bad_typeid (см. п. п. 18.5.3 в [1]). В качестве имени типа используются имена классов. Однако в отличие от dynamic__cast<>, оператор typeidO можно применять к встроенным типам. Полезного в этом мало, но ошибки не вызывает.
Так как оператор typeidO возвращает объект типа type_info, то можно сравнивать эти объекты и вызывать методы класса type_i nf о. В справочной системе С++ Borland 6 есть пример, иллюстрирующий простейший случай использования оператора typeidO. Мы его модифицируем и дополним (листинг 10.7).
Листинг 10.7. Простое использование оператора typeidO
class D{}; // базовый класс class В: D {}; // наследник int main() { char С: float,X: if (typeid(C) == typeid(X)) // сравнили типы
cout << "С и X - одного типа!" << endl; else cout << "С и X - разного типа! " << endl;
cout << typeid(int).name(); // выводит int
cout << typeid(double).name(); // выводит double
cout <<boolapha <<
(typeid(int).before(typeid(double))?true:false) << endl; // выводит false
cout << typeid(D).name(); // выводит D
cout << typeid(B).name(); // выводит В
cout <<boolapha <<
(typeid(D).before(typeid(B))?true:false) << endl; // выводит false int iobj;
cout << typeid(iobj).name(); // выводит int
out << typeid(8.16).name(); // выводит double }
Опубликовал Kest
December 03 2013 01:13:37 ·
0 Комментариев ·
5001 Прочтений ·
• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •
Комментарии
Нет комментариев.
Добавить комментарий
Рейтинги
Рейтинг доступен только для пользователей.
Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.
Нет данных для оценки.
Гость
Вы не зарегистрированны? Нажмите здесь для регистрации.