stringtranslate.com

Информация о типе времени выполнения

В программировании информация о типе во время выполнения или идентификация типа во время выполнения ( RTTI ) [1] является функцией некоторых языков программирования (таких как C++ , [2] Object Pascal и Ada [3] ), которая раскрывает информацию о типе данных объекта во время выполнения . Информация о типе во время выполнения может быть доступна для всех типов или только для типов, которые явно имеют ее (как в случае с Ada). Информация о типе во время выполнения является специализацией более общей концепции, называемой интроспекцией типа .

В оригинальном проекте C++ Бьярне Страуструп не включил информацию о типе времени выполнения, поскольку считал, что этот механизм часто используется неправильно. [4]

Обзор

В C++ RTTI может использоваться для выполнения безопасных приведений типов с помощью dynamic_cast<>оператора и для манипулирования информацией о типе во время выполнения с помощью typeidоператора и std::type_infoкласса. В Object Pascal RTTI может использоваться для выполнения безопасных приведений типов с помощью asоператора, проверки класса, к которому принадлежит объект is, с помощью оператора и манипулирования информацией о типе во время выполнения с помощью классов, содержащихся в RTTIмодуле [5] (т. е. классов: TRttiContext , TRttiInstanceType и т. д.). В Ada объекты тегированных типов также хранят тег типа, который позволяет идентифицировать тип этих объектов во время выполнения. Оператор inможет использоваться для проверки во время выполнения, имеет ли объект определенный тип и может ли он быть безопасно преобразован в него. [6]

RTTI доступен только для классов, которые являются полиморфными , что означает, что они имеют по крайней мере один виртуальный метод . На практике это не является ограничением, поскольку базовые классы должны иметь виртуальный деструктор , чтобы позволить объектам производных классов выполнять надлежащую очистку, если они удаляются из базового указателя.

Некоторые компиляторы имеют флаги для отключения RTTI. Использование этих флагов может уменьшить общий размер приложения, что делает их особенно полезными при работе с системами с ограниченным объемом памяти. [7]

С++ –типид

Зарезервированное typeid слово (ключевое слово) используется для определения класса объекта во время выполнения. Оно возвращает ссылку на объект, который существует до конца программы. [8] Использование в неполиморфном контексте часто предпочтительнее, чем в ситуациях , когда нужна только информация о классе, поскольку это всегда процедура с постоянным временем выполнения, тогда как может потребоваться пройти по решетке вывода класса своего аргумента во время выполнения. [ необходима цитата ] Некоторые аспекты возвращаемого объекта определяются реализацией, например , и на них нельзя полагаться в разных компиляторах для обеспечения согласованности.std::type_infotypeiddynamic_cast<class_type>typeiddynamic_caststd::type_info::name()

Объекты класса std::bad_typeidвыбрасываются, когда выражение for typeidявляется результатом применения унарного оператора * к нулевому указателю . Выбрасывается ли исключение для других аргументов нулевой ссылки, зависит от реализации. Другими словами, чтобы исключение было гарантировано, выражение должно иметь вид, typeid(*p)где p— любое выражение, приводящее к нулевому указателю.

Пример

#include <iostream> #include <typeinfo>  класс Person { public : virtual ~ Person () = default ; };      класс Сотрудник : публичный Человек {};     int main () { Person person ; Employee employee ; Person * ptr = & employee ; Person & ref = employee ; // Строка, возвращаемая typeid::name, определяется реализацией. std :: cout << typeid ( person ). name () << std :: endl ; // Person (статически известен во время компиляции). std :: cout << typeid ( employee ). name () << std :: endl ; // Employee (статически известен во время компиляции). std :: cout << typeid ( ptr ). name () << std :: endl ; // Person* (статически известен во время компиляции). std :: cout << typeid ( * ptr ). name () << std :: endl ; // Employee (ищет динамически во время выполнения, // поскольку это разыменование указателя // на полиморфный класс). std :: cout << typeid ( ref ). name () << std :: endl ; // Сотрудник (ссылки также могут быть полиморфными)                                                 Person * p = nullptr ; try { typeid ( * p ); // Не неопределенное поведение; выдает std::bad_typeid. } catch (...) { }              Person & p_ref = * p ; // Неопределенное поведение: разыменование null typeid ( p_ref ); // не соответствует требованиям для генерации std::bad_typeid // потому что выражение для typeid не является результатом // применения унарного оператора *. }        

Вывод (точный вывод зависит от системы и компилятора):

ЧеловекСотрудникЧеловек*СотрудникСотрудник

С++ –dynamic_castи Java-трансляция

Оператор dynamic_castв C++ используется для приведения ссылки или указателя к более конкретному типу в иерархии классов . В отличие от static_cast, целью dynamic_castдолжен быть указатель или ссылка на класс . В отличие от static_castи приведения типов в стиле C (где проверка типов происходит во время компиляции), проверка безопасности типов выполняется во время выполнения. Если типы несовместимы, будет сгенерировано исключение (при работе со ссылками ) или будет возвращен нулевой указатель (при работе с указателями ).

Приведение типа в Javajava.lang.ClassCastException ведет себя аналогичным образом: если преобразуемый объект на самом деле не является экземпляром целевого типа и не может быть преобразован в него методом, определенным в языке, будет выдан экземпляр . [9]

Пример

Предположим, что некоторая функция принимает объект типа в качестве аргумента и хочет выполнить некоторую дополнительную операцию , Aесли переданный объект является экземпляром B, подклассомA . Это можно сделать dynamic_castследующим образом.

#include <массив> #include <поток_вывода> #include <память> #include <тип_информации>    с использованием пространства имен std ;  class A { public : // Поскольку RTTI включен в таблицу виртуальных методов, должна быть по крайней мере // одна виртуальная функция. virtual ~ A () = default ;         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 = dynamic_cast < B &> ( my_a ); my_b . MethodSpecificToB (); } catch ( const bad_cast & e ) { cerr << " Исключение " << e . what () << " выдано." << endl ; cerr << " Объект не относится к типу B" << endl ; } }                                int main () { array < 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 < A > (); // Указатель на объект A.                   для ( int i = 0 ; i < 3 ; ++ i ) МояФункция ( * 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 (); иначе std :: cerr << "Объект не является типом B" << std :: endl ; }          

Объект Паскаль, Дельфи

В Object Pascal и Delphi оператор isиспользуется для проверки типа класса во время выполнения. Он проверяет принадлежность объекта к данному классу, включая классы отдельных предков, присутствующих в дереве иерархии наследования (например, Button1 — это класс TButton , имеющий предков: TWinControlTControlTComponentTPersistentTObject , где последний является предком всех классов). Оператор asиспользуется, когда объект необходимо обрабатывать во время выполнения так, как если бы он принадлежал классу-предку.

Модуль RTTI используется для манипулирования информацией о типе объекта во время выполнения. Этот модуль содержит набор классов, которые позволяют: получать информацию о классе объекта и его предках, свойствах, методах и событиях, изменять значения свойств и вызывать методы. В следующем примере показано использование модуля RTTI для получения информации о классе, к которому принадлежит объект, его создании и вызове его метода. В примере предполагается, что класс TSubject был объявлен в модуле с именем SubjectUnit.

использует RTTI , SubjectUnit ;  procedure WithoutReflection ; var MySubject : TSubject ; begin MySubject := TSubject . Create ; try Subject . Hello ; finally Subject . Free ; end ; end ;           procedure WithReflection ; var RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Subject : TObject ; begin RttiType := RttiContext . FindType ( 'SubjectUnit.TSubject' ) as TRttiInstanceType ; Subject := RttiType . GetMethod ( 'Create' ) . Invoke ( RttiType . MetaclassType , []) . AsObject ; try RttiType . GetMethod ( 'Hello' ) . Invoke ( Subject , []) ; finally Subject . Free ; end ; end ;                      

Смотрите также

Ссылки

  1. ^ Sun Microsystems (2000). "Runtime Type Identification". C++ Programming Guide . Oracle . Получено 16 апреля 2015 г. .
  2. ^ "Библиотека поддержки языка [support.rtti]". eel.is . Получено 2021-07-13 .
  3. ^ "Объектно-ориентированное программирование". learn.adacore.com . Получено 2021-07-13 .
  4. ^ Бьерн Страуструп (март 1993 г.). «История C++: 1979–1991» (PDF) . Бьерн Страуструп. п. 50 . Проверено 18 мая 2009 г.
  5. ^ "Работа с RTTI - RAD Studio". docwiki.embarcadero.com . Получено 2021-06-06 .
  6. ^ Инглиш, Джон (2002-02-22). "Глава 15". Ada 95: Искусство объектно-ориентированного программирования . Получено 2021-07-13 .
  7. ^ "Избегание RTTI и поддержка -fno-rtti в Arm Compiler 6". Разработчик Arm . Получено 2021-07-13 .
  8. ^ Стандарт C++ (ISO/IEC14882) раздел 5.2.8 [expr.typeid], 18.5.1 [lib.type.info] – http://cs.nyu.edu/courses/fall11/CSCI-GA.2110-003/documents/c++2003std.pdf
  9. ^ «ClassCastException (платформа Java SE 8)».

Внешние ссылки