Из Википедии, свободной энциклопедии
  (Перенаправлено из динамического приведения )
Перейти к навигации Перейти к поиску

В компьютерном программировании, информации времени выполнения типа или идентификации типа во время выполнения ( 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>typeiddynamic_caststd::type_info::name(), и нельзя полагаться на согласованность между компиляторами.

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

Пример [ править ]

#include  <iostream>#include  <typeinfo>class  Person  { public :  virtual  ~ Person ()  =  default ; };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 ++)

Ссылки [ править ]

  1. ^ Sun Microsystems (2000). «Идентификация типа среды выполнения» . Руководство по программированию на C ++ . Oracle . Проверено 16 апреля 2015 года .
  2. ^ Бьярне Страуструп (март 1993). «История C ++: 1979—1991» (PDF) . Бьярне Страуструп. п. 50 . Проверено 18 мая 2009 .
  3. ^ Стандарт 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
  4. ^ http://docs.oracle.com/javase/8/docs/api/java/lang/ClassCastException.html

Внешние ссылки [ править ]

  • dynamic_cast оператор в IBM Mac OS X Compilers
  • dynamic_cast оператор в MSDN