19.2.2. Оператор typeid
Второй оператор поддержки RTTI — это оператор typeid. Оператор typeid позволяет выяснить текущий тип объекта.
Выражение typeid имеет форму typeid(е), где е — любое выражение или имя типа. Результатом оператора typeid является ссылка на константный объект библиотечного типа type_info или типа, открыто производного от него. В разделе 19.2.4 этот тип рассматривается более подробно. Класс type_info определен в заголовке typeinfo.
Оператор typeid применим к выражениям любого типа. Как обычно, спецификатор const верхнего уровня (см. раздел 2.4.3) игнорируется, и если выражение является ссылкой, то оператор typeid возвращает тип, на который ссылается ссылка. Но при применении к массиву или функции стандартное преобразование в указатель (см. раздел 4.11.2) не осуществляется. Таким образом, результат выражения typeid(a), где а является массивом, описывает тип массива, а не тип указателя.
Когда операнд не имеет типа класса или является классом без виртуальных функций, оператор typeid возвращает статический тип операнда. Когда операнд является l-значением типа класса, определяющим по крайней мере одну виртуальную функцию, тип результата вычисляется во время выполнения.
Использование оператора typeid
Чаще всего оператор typeid используют для сравнения типов двух выражений или для сравнения типа выражения с определенным типом:
Derived *dp = new Derived;
Base *bp = dp; // оба указателя указывают на объект Derived
// сравнить типы двух объектов во время выполнения
if (typeid(*bp) == typeid(*dp)) {
// bp и dp указывают на объекты того же типа
}
// проверить, совпадает ли тип времени выполнения с указанным типом
if (typeid(*bp) == typeid(Derived)) {
// bp на самом деле указывает на класс Derived
}
В первом операторе if сравниваются динамические типы объектов, на которые указывают указатели bp и dp. Если оба указателя указывают на тот же тип, то условие истинно. Точно так же второй оператор if истин, если указатель bp в настоящее время указывает на объект класса Derived.
Обратите внимание: операндами оператора typeid являются проверяемые объекты (*bp), а не указатели (bp).
// результат проверки всегда ложный: тип bp - указатель на класс Base
if (typeid(bp) == typeid(Derived)) {
// код, который никогда не будет выполнен
}
Это условие сравнивает тип Base* с типом Derived. Хотя указатель указывает на объект типа класса, обладающего виртуальными функциями, сам указатель не является объектом типа класса. Тип Base* может быть вычислен и вычисляется во время компиляции. Этот тип не совпадает с типом Derived, поэтому условие всегда будет ложно, независимо от типа объекта, на который указывает указатель bp.
Применение оператора typeid к указателю (в отличие от объекта, на который указывает указатель) возвращает статический тип времени компиляции указателя.
Оператор typeid требует, чтобы проверка во время выполнения определила, обрабатывается ли выражение. Компилятор обрабатывает выражение, только если у типа есть виртуальные функции. Если у типа нет никаких виртуальных функций, то оператор typeid возвращает статический тип выражения; статический тип известен компилятору и без вычисления выражения.
Если динамический тип выражения может отличаться от статического, то выражение следует вычислить (во время выполнения), чтобы определить результирующий тип. Это различие имеет значение при выполнении оператора typeid(*p). Если p указывает на тип без виртуальных функций, то указатель p не обязан быть допустимым указателем. В противном случае выражение *p вычисляется во время выполнения, тогда указатель p обязан быть допустимым. Если указатель p пуст, то выражение typeid(*p) передаст исключение bad_typeid.
Упражнения раздела 19.2.2
Упражнение 19.6. Напишите выражение для динамического приведения указателя на тип Query_base к указателю на тип AndQuery (см. раздел 15.9.1). Проверьте приведение, используя объект класса AndQuery и класса другого запроса. Выведите сообщение, подтверждающее работоспособность приведения, и убедитесь, что вывод соответствует ожиданиям.
Упражнение 19.7. Напишите то же приведение, но приведите объект класса Query_base к ссылке на тип AndQuery. Повторите проверку и удостоверьтесь в правильности работы приведения.
Упражнение 19.8. Напишите выражение typeid, чтобы убедиться, указывают ли два указателя на класс Query_base на тот же тип. Затем проверьте, не является ли этот тип классом AndQuery.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОК