stringtranslate.com

Información de tipo de tiempo de ejecución

En programación de computadoras, la información de tipo de tiempo de ejecución o identificación de tipo de tiempo de ejecución ( RTTI ) [1] es una característica de algunos lenguajes de programación (como C++ , [2] Object Pascal y Ada [3] ) que expone información sobre un Tipo de datos del objeto en tiempo de ejecución . La información de tipo en tiempo de ejecución puede estar disponible para todos los tipos o solo para los tipos que la tienen explícitamente (como es el caso de Ada). La información de tipos en tiempo de ejecución es una especialización de un concepto más general llamado introspección de tipos .

En el diseño original de C++, Bjarne Stroustrup no incluía información de tipo de tiempo de ejecución porque pensaba que este mecanismo a menudo se usaba incorrectamente. [4]

Descripción general

En C++, RTTI se puede usar para realizar encasillamientos seguros usando el dynamic_cast<>operador y para manipular información de tipo en tiempo de ejecución usando el typeidoperador y std::type_infola clase. En Object Pascal, RTTI se puede utilizar para realizar conversiones de tipos seguras con el asoperador, probar la clase a la que pertenece un objeto con el isoperador y manipular información de tipo en tiempo de ejecución con clases contenidas en la RTTIunidad [5] (es decir, clases: TRttiContext , TRttiInstanceType , etc.). En Ada, los objetos de tipos etiquetados también almacenan una etiqueta de tipo, que permite la identificación del tipo de estos objetos en tiempo de ejecución. El inoperador se puede utilizar para probar, en tiempo de ejecución, si un objeto es de un tipo específico y se puede convertir a él de forma segura. [6]

RTTI está disponible sólo para clases que son polimórficas , lo que significa que tienen al menos un método virtual . En la práctica, esto no es una limitación porque las clases base deben tener un destructor virtual para permitir que los objetos de las clases derivadas realicen una limpieza adecuada si se eliminan de un puntero base.

Algunos compiladores tienen indicadores para desactivar RTTI. El uso de estos indicadores puede reducir el tamaño general de la aplicación, lo que los hace especialmente útiles cuando se dirigen a sistemas con una cantidad limitada de memoria. [7]

C++ – ID de tipo

La typeid palabra reservada (palabra clave) se utiliza para determinar la clase de un objeto en tiempo de ejecución. Devuelve una referencia al std::type_infoobjeto, que existe hasta el final del programa. [8] El uso de typeid, en un contexto no polimórfico, a menudo se prefiere a situaciones donde solo se necesita la información de clase, porque siempre es un procedimiento de tiempo constante , mientras que es posible que sea necesario atravesar la red de derivación de clase de su argumento en tiempo de ejecución. [ cita necesaria ] Algunos aspectos del objeto devuelto están definidos por la implementación, como , y no se puede confiar en que todos los compiladores sean consistentes.dynamic_cast<class_type>typeiddynamic_caststd::type_info::name()

Los objetos de clase std::bad_typeidse lanzan cuando la expresión for typeides el resultado de aplicar el operador unario * en un puntero nulo . El hecho de que se produzca una excepción para otros argumentos de referencia nulos depende de la implementación. En otras palabras, para que se garantice la excepción, la expresión debe tomar la forma typeid(*p)donde pestá cualquier expresión que resulte en un puntero nulo.

Ejemplo

#incluir <iostream> #incluir <tipoinfo>  clase Persona { público : virtual ~ Persona () = predeterminado ; };      clase Empleado : Persona pública {};     int main () { Persona persona ; Empleado empleado ; Persona * ptr = & empleado ; Persona & ref = empleado ; // La cadena devuelta por typeid::name está definida por la implementación. std :: cout << typeid ( persona ). nombre () << std :: endl ; // Persona (conocida estáticamente en tiempo de compilación). std :: cout << typeid ( empleado ). nombre () << std :: endl ; // Empleado (conocido estáticamente en tiempo de compilación). std :: cout << typeid ( ptr ). nombre () << std :: endl ; // Persona* (conocida estáticamente en tiempo de compilación). std :: cout << typeid ( * ptr ). nombre () << std :: endl ; // Empleado (buscado dinámicamente en tiempo de ejecución // porque es la desreferencia de un // puntero a una clase polimórfica). std :: cout << typeid ( ref ). nombre () << std :: endl ; // Empleado (las referencias también pueden ser polimórficas)                                                 Persona * p = nullptr ; prueba { typeid ( * p ); // Comportamiento no indefinido; lanza std::bad_typeid. } atrapar (...) { }              Persona & p_ref = * p ; // Comportamiento indefinido: desreferenciación de typeid nulo ( p_ref ); // no cumple con los requisitos para lanzar std::bad_typeid // porque la expresión para typeid no es el resultado // de aplicar el operador unario *. }        

Salida (la salida exacta varía según el sistema y el compilador):

PersonaEmpleadoPersona*EmpleadoEmpleado

C++: transmisión dinámica y conversión de Java

El dynamic_castoperador en C++ se utiliza para reducir una referencia o un puntero a un tipo más específico en la jerarquía de clases . A diferencia de static_cast, el objetivo de dynamic_castdebe ser un puntero o referencia a la clase . A diferencia static_castdel encasillado estilo C (donde se produce la verificación de tipos durante la compilación), se realiza una verificación de seguridad de tipos en tiempo de ejecución. Si los tipos no son compatibles, se generará una excepción (cuando se trate de referencias ) o se devolverá un puntero nulo (cuando se trate de punteros ).

Un encasillamiento de Java se comporta de manera similar; Si el objeto que se está convirtiendo no es en realidad una instancia del tipo de destino y no se puede convertir en uno mediante un método definido por el lenguaje, java.lang.ClassCastExceptionse generará una instancia de. [9]

Ejemplo

Supongamos que alguna función toma un objeto de tipo Acomo argumento y desea realizar alguna operación adicional si el objeto pasado es una instancia de B, una subclase de A. Esto se puede hacer usando dynamic_castlo siguiente.

#include <matriz> #include <iostream> #include <memoria> #include <typeinfo>    usando el espacio de nombres estándar ;  class A { public : // Dado que RTTI está incluido en la tabla de métodos virtuales, debe haber al menos // una función virtual. virtual ~ A () = predeterminado ;         void MethodSpecificToA () { cout << "Se invocó el método específico para A" << endl ; } };        clase B : public A { public : void MethodSpecificToB () { cout << "Se invocó el método específico para B" << endl ; } };             void MyFunction ( A & my_a ) { try { // La transmisión se realizará correctamente solo para objetos de tipo B. B & mi_b = transmisión_dinámica < B &> ( mi_a ); mi b . MétodoEspecíficoToB (); } catch ( const bad_cast & e ) { cerr << " Excepción " << e . qué () << "lanzado." << fin ; cerr << "El objeto no es de tipo B" << endl ; } }                                int main ( ) { matriz < único_ptr <A> , 3 > matriz_de_a ;// Matriz de punteros a la clase base A. array_of_a [ 0 ] = make_unique < B > (); // Puntero al objeto B. array_of_a [ 1 ] = make_unique < B > (); // Puntero al objeto B. array_of_a [ 2 ] = make_unique < A > (); // Puntero a un objeto.                   for ( int i = 0 ; i < 3 ; ++ i ) MiFunción ( * array_of_a [ i ]); }         

Salida de consola:

Se invocó el método específico para BSe invocó el método específico para BExcepción std::bad_cast lanzada.El objeto no es del tipo B.

MyFunctionSe puede escribir una versión similar con punteros en lugar de referencias :

void MiFunción ( A * mi_a ) { B * mi_b = Dynamic_cast < B *> ( mi_a );        if ( my_b != nullptr ) my_b -> métodoEspecíficoToB (); else std :: cerr << "El objeto no es tipo B" << std :: endl ; }          

Objeto Pascal, Delfos

En Object Pascal y Delphi , el operador isse utiliza para verificar el tipo de una clase en tiempo de ejecución. Comprueba la pertenencia de un objeto a una clase determinada, incluidas las clases de ancestros individuales presentes en el árbol de jerarquía de herencia (por ejemplo, Button1 es una clase TButton que tiene ancestros: TWinControlTControlTComponentTPersistentTObject , donde este último es el ancestro de todas las clases). El operador asse utiliza cuando un objeto necesita ser tratado en tiempo de ejecución como si perteneciera a una clase ancestral.

La unidad RTTI se utiliza para manipular información de tipo de objeto en tiempo de ejecución. Esta unidad contiene un conjunto de clases que le permiten: obtener información sobre la clase de un objeto y sus antepasados, propiedades, métodos y eventos, cambiar valores de propiedades y llamar a métodos. El siguiente ejemplo muestra el uso del módulo RTTI para obtener información sobre la clase a la que pertenece un objeto, crearlo y llamar a su método. El ejemplo supone que la clase TSubject se ha declarado en una unidad denominada SubjectUnit.

utiliza RTTI , SubjectUnit ;  procedimiento SinReflexión ; var MiAsunto : TSubject ; comenzar MiAsunto : = TSubject . Crear ; prueba Asunto . Hola ; finalmente Asunto . Gratis ; fin ; fin ;           procedimiento ConReflexión ; var RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Asunto : TObjeto ; comenzar RttiType : = RttiContext . FindType ( 'SubjectUnit.TSubject' ) como TRttiInstanceType ; Asunto : = RttiType . GetMethod ( 'Crear' ) . Invocar ( RttiType . MetaclassType , []) . ComoObjeto ; prueba RttiType . GetMethod ( 'Hola' ) . Invocar ( Asunto , []) ; finalmente Asunto . Gratis ; fin ; fin ;                      

Ver también

Referencias

  1. ^ Microsistemas solares (2000). "Identificación del tipo de tiempo de ejecución". Guía de programación en C++ . Oráculo . Consultado el 16 de abril de 2015 .
  2. ^ "Biblioteca de soporte de idiomas [support.rtti]". anguila.es . Consultado el 13 de julio de 2021 .
  3. ^ "Programación orientada a objetos". aprender.adacore.com . Consultado el 13 de julio de 2021 .
  4. ^ Bjarne Stroustrup (marzo de 1993). "Una historia de C++: 1979—1991" (PDF) . Bjarne Stroustrup. pag. 50 . Consultado el 18 de mayo de 2009 .
  5. ^ "Trabajar con RTTI - RAD Studio". docwiki.embarcadero.com . Consultado el 6 de junio de 2021 .
  6. ^ Inglés, John (22 de febrero de 2002). "Capítulo 15". Ada 95: El arte de la programación orientada a objetos . Consultado el 13 de julio de 2021 .
  7. ^ "Evitar RTTI y compatibilidad con -fno-rtti en Arm Compiler 6". Desarrollador de brazo . Consultado el 13 de julio de 2021 .
  8. ^ Estándar C++ (ISO/IEC14882) sección 5.2.8 [expr.typeid], 18.5.1 [lib.type.info] – http://cs.nyu.edu/courses/fall11/CSCI-GA.2110-003 /documentos/c++2003std.pdf
  9. ^ "ClassCastException (Plataforma Java SE 8)".

enlaces externos