Эта статья требует внимания эксперта в области вычислительной техники . Октябрь 2019 г. ) ( |
В компьютерном программировании, информации времени выполнения типа или идентификации типа во время выполнения ( RTTI ) [1] является особенностью C ++ языка программирования , который предоставляет информация о объекте типа данных на время выполнения . Информация о типах времени выполнения может применяться к простым типам данных, таким как целые числа и символы, или к универсальным типам. Это специализация C ++ более общей концепции, называемой интроспекцией типов . Подобные механизмы известны и в других языках программирования, таких как Object Pascal ( Delphi ).
В исходной конструкции C ++ Бьярн Страуструп не включил информацию о типах во время выполнения, поскольку считал, что этот механизм часто используется не по назначению. [2]
Обзор [ править ]
В C ++ RTTI можно использовать для безопасного приведения типов с помощью dynamic_cast<>
оператора и для управления информацией о типе во время выполнения с помощью typeid
оператора и std::type_info
класса.
RTTI доступен только для полиморфных классов , что означает, что у них есть хотя бы один виртуальный метод . На практике это не ограничение, потому что базовые классы должны иметь виртуальный деструктор, чтобы позволить объектам производных классов выполнять надлежащую очистку, если они удалены из базового указателя.
RTTI является необязательным для некоторых компиляторов; программист может выбрать во время компиляции, включать ли эту функциональность. Доступность RTTI может потребовать значительных ресурсов, даже если программа его не использует.
typeid [ править ]
typeid
Ключевое слово используется для определения класса в качестве объекта на время выполнения . Возвращает ссылку на std::type_info
объект, существующий до конца программы. [3] Использование typeid
в неполиморфном контексте часто предпочтительнее в ситуациях, когда требуется только информация о классе, потому что это всегда процедура с постоянным временем , тогда как может потребоваться пересечь решетку деривации классов своего аргумента в время выполнения. [ необходима цитата ] Некоторые аспекты возвращаемого объекта определяются реализацией, напримерdynamic_cast<class_type>
typeid
dynamic_cast
std::type_info::name()
, и нельзя полагаться на согласованность между компиляторами.
Объекты класса std::bad_typeid
выбрасываются, когда выражение для typeid
является результатом применения унарного оператора * к нулевому указателю . Создание исключения для других аргументов нулевой ссылки зависит от реализации. Другими словами, чтобы исключение было гарантировано, выражение должно иметь форму typeid(*p)
где p
- любое выражение, приводящее к нулевому указателю.
Пример [ править ]
#include <iostream>#include <typeinfo>класс Person { общедоступный : виртуальный ~ Person () = по умолчанию ; };class Employee : public Person {};int main () { Человек person ; Сотрудник сотрудник ; Человек * ptr = & employee ; Человек & ref = сотрудник ; // Строка, возвращаемая typeid :: name, определяется реализацией. std :: cout << typeid ( человек ). имя () << std :: endl ; // Человек (статически известен во время компиляции). std :: cout << typeid ( сотрудник ). имя () << std :: endl ; // Сотрудник (статически известен во время компиляции). std :: cout << typeid ( ptr ). имя () << std :: endl ; // Человек * (статически известен во время компиляции). std :: cout << typeid ( * ptr ). имя () << std :: endl ; // Сотрудник (просматривается динамически во время выполнения // потому что это разыменование указателя // на полиморфный класс). std :: cout << typeid ( ref ). имя () << std :: endl ; // Сотрудник (ссылки также могут быть полиморфными) Человек * p = nullptr ; попробуйте { typeid ( * p ); // Не неопределенное поведение; выбрасывает std :: bad_typeid. } поймать (...) { } Человек & p_ref = * p ; // Неопределенное поведение: разыменование null typeid ( p_ref ); // не соответствует требованиям для выдачи std :: bad_typeid // потому что выражение для typeid не является результатом // применения унарного оператора *. }
Вывод (точный вывод зависит от системы и компилятора):
ЧеловекРаботникЧеловек*РаботникРаботник
dynamic_cast и Java cast [ править ]
dynamic_cast
Оператор в C ++ используется для понижающего приведения ссылки или указателя на более конкретный тип в иерархии классов . В отличие от static_cast
, целью класса dynamic_cast
должен быть указатель или ссылка на класс . В отличие от приведения типов в стиле Cstatic_cast
и (где проверка типа выполняется во время компиляции), проверка безопасности типа выполняется во время выполнения . Если типы несовместимы, будет выброшено исключение (при работе со ссылками ) или будет возвращен нулевой указатель (при работе с указателями ).
Приведение типов в Java ведет себя аналогичным образом; если приводимый объект на самом деле не является экземпляром целевого типа и не может быть преобразован в один с помощью метода, определенного языком, java.lang.ClassCastException
будет брошен экземпляр . [4]
Пример [ править ]
Предположим , что некоторая функция принимает объект типа в A
качестве аргумента, и желает выполнить некоторую дополнительную работу , если переданный объект является экземпляром B
, в подклассе из A
. Это можно сделать dynamic_cast
следующим образом.
#include <массив>#include <iostream>#include <память>#include <typeinfo>используя пространство имен std ;class A { public : // Поскольку RTTI включен в таблицу виртуальных методов, должна быть // как минимум одна виртуальная функция. виртуальный ~ A () = по умолчанию ; void MethodSpecificToA () { cout << "Метод, специфичный для A, был вызван" << endl ; } };class B : public A { public : void MethodSpecificToB () { cout << "Метод, специфичный для B, был вызван" << endl ; } };void MyFunction ( A & my_a ) { try { // Приведение будет успешным только для объектов типа B. B & my_b = динамическое_кастирование < B &> ( my_a ); my_b . MethodSpecificToB (); } catch ( const bad_cast & e ) { cerr << "Исключение" << e . what () << "брошено." << endl ; Cerr << "Объект не относится к типу B" << endl ; } }int main () { массив < unique_ptr < A > , 3 > array_of_a ; // Массив указателей на базовый класс A. array_of_a [ 0 ] = make_unique < B > (); // Указатель на объект B. array_of_a [ 1 ] = make_unique < B > (); // Указатель на объект B. array_of_a [ 2 ] = make_unique < > (); // Указатель на объект. for ( int i = 0 ; i < 3 ; ++ i ) MyFunction ( * array_of_a [ i ]); }
Вывод в консоль:
Был вызван метод, специфичный для BБыл вызван метод, специфичный для BВыброшено исключение std :: bad_cast.Объект не типа B
Аналогичный вариант MyFunction
можно написать с указателями вместо ссылок :
void MyFunction ( A * my_a ) { B * my_b = dynamic_cast < B *> ( my_a ); если ( my_b ! = nullptr ) my_b -> methodSpecificToB (); else std :: cerr << "Объект не относится к типу B" << std :: endl ; }
См. Также [ править ]
- Вывод типа
- Типа самоанализ
- тип
- Отражение (информатика)
- Шаблон (C ++)
Ссылки [ править ]
- ^ Sun Microsystems (2000). «Идентификация типа среды выполнения» . Руководство по программированию на C ++ . Oracle . Проверено 16 апреля 2015 года .
- ^ Бьярне Страуструп (март 1993). «История C ++: 1979—1991» (PDF) . Бьярне Страуструп. п. 50 . Проверено 18 мая 2009 .
- ^ Стандарт C ++ (ISO / IEC14882) раздел 5.2.8 [expr.typeid], 18.5.1 [lib.type.info] - http://cs.nyu.edu/courses/fall11/CSCI-GA.2110- 003 / документы / c ++ 2003std.pdf
- ^ http://docs.oracle.com/javase/8/docs/api/java/lang/ClassCastException.html
Внешние ссылки [ править ]
- dynamic_cast оператор в IBM Mac OS X Compilers
- dynamic_cast оператор в MSDN