Informació del tipus en temps d'execució
En programació informàtica, la informació de tipus en temps d'execució o identificació de tipus en temps d'execució (RTTI)[1] és una característica d'alguns llenguatges de programació (com ara C++,[2] Object Pascal i Ada[3]) que exposa informació sobre el tipus de dades d'un objecte en temps d'execució. La informació de tipus en temps d'execució pot estar disponible per a tots els tipus o només per als tipus que la tenen explícitament (com és el cas d'Ada). La informació de tipus en temps d'execució és una especialització d'un concepte més general anomenat introspecció de tipus.
En el disseny original de C++, Bjarne Stroustrup no va incloure informació de tipus en temps d'execució, perquè pensava que aquest mecanisme sovint s'utilitzava malament.[4]
Visió general
[modifica]En C++, RTTI es pot utilitzar per fer conversions de tipus segures utilitzant l'operador dynamic_cast<> i per manipular informació de tipus en temps d'execució utilitzant l'operador typeid i la classe std::type_info. En Object Pascal, RTTI es pot utilitzar per realitzar conversions de tipus segures amb l'operador as, provar la classe a la qual pertany un objecte amb l'operador is i manipular informació de tipus en temps d'execució amb classes contingudes a la unitat RTTI[5] (és a dir, classes: TRttiContext, TRttiInstanceType, etc.). En Ada, els objectes de tipus etiquetats també emmagatzemen una etiqueta de tipus, que permet la identificació del tipus d'aquests objectes en temps d'execució. L'operador in es pot utilitzar per provar, en temps d'execució, si un objecte és d'un tipus específic i es pot convertir-hi de manera segura.[6]
RTTI només està disponible per a classes polimòrfiques, és a dir, que tenen com a mínim un mètode virtual. A la pràctica, això no és una limitació, ja que les classes base han de tenir un destructor virtual per permetre que els objectes de les classes derivades realitzin una neteja adequada si s'eliminen d'un punter base.
Alguns compiladors tenen indicadors per desactivar RTTI. L'ús d'aquests indicadors pot reduir la mida general de l'aplicació, cosa que els fa especialment útils quan es dirigeixen a sistemes amb una quantitat limitada de memòria.[7]
Operador typeid C++
[modifica]La paraula reservada (paraula clau) typeid s'utilitza per determinar la classe d'un objecte en temps d'execució. Retorna una referència a l'objecte std::type_info, que existeix fins al final del programa. L'ús de typeid, en un context no polimòrfic, sovint es prefereix a dynamic_cast< class_type > en situacions on només es necessita la informació de la classe, perquè typeid sempre és un procediment de temps constant, mentre que dynamic_cast pot necessitar recórrer la xarxa de derivació de classes del seu argument en temps d'execució. Alguns aspectes de l'objecte retornat estan definits per la implementació, com ara std::type_info::name(), i no es pot confiar en la coherència entre compiladors.
Els objectes de la classe std::bad_typeid es llancen quan l'expressió per a typeid és el resultat d'aplicar l'operador unari * a un punter nul. El fet que es llanci una excepció per a altres arguments de referència nuls depèn de la implementació. En altres paraules, perquè l'excepció estigui garantida, l'expressió ha de prendre la forma typeid(*p), on p és qualsevol expressió que doni lloc a un punter nul.
L'operador typeid, si s'utilitza en un context on std::type_info no és visible, està mal informat, és a dir, <typeinfo> s'ha d'incloure cada vegada que s'utilitza. Actualment, import std ; no admet typeid sense #include <typeinfo>.
Exemple
[modifica]#include <typeinfo>
import std;
class Person {
public:
virtual ~Person() = default;
};
class Employee: public Person {
// ...
};
int main() {
Person person;
Employee employee;
Person* ptr = &employee;
Person& ref = employee;
// The string returned by typeid::name is implementation-defined.
std::println("{}", typeid(person).name());
// Person (statically known at compile-time).
std::println("{}", typeid(employee).name());
// Employee (statically known at compile-time).
std::println("{}", typeid(ptr).name());
// Person* (statically known at compile-time).
std::println("{}", typeid(*ptr).name());
// Employee (looked up dynamically at run-time
// because it is the dereference of a
// pointer to a polymorphic class).
std::println("{}", typeid(ref).name());
// Employee (references can also be polymorphic)
Person* p = nullptr;
try {
typeid(*p); // Not undefined behavior; throws std::bad_typeid.
} catch (const std::bad_typeid& e) {
std::println(stderr, "Exception caught: {}", e.what());
}
Person& p_ref = *p; // Undefined behavior: dereferencing null
typeid(p_ref); // does not meet requirements to throw std::bad_typeid
// because the expression for typeid is not the result
// of applying the unary * operator.
}
Sortida (la sortida exacta varia segons el sistema i el compilador):
Person Employee Person* Employee Employee
Referències
[modifica]- ↑ Sun Microsystems. «Runtime Type Identification» (en anglès). C++ Programming Guide. Oracle. [Consulta: 16 abril 2015].
- ↑ «Language support library [support.rtti]» (en anglès). eel.is. [Consulta: 13 juliol 2021].
- ↑ «Object-oriented programming» (en anglès). learn.adacore.com. [Consulta: 13 juliol 2021].
- ↑ Error: hi ha arxiuurl o arxiudata, però calen tots dos paràmetres.Bjarne Stroustrup. «[Bjarne Stroustrup A History of C++: 1979—1991]» (en anglès). Bjarne Stroustrup, 01-03-1993. [Consulta: 18 maig 2009].
- ↑ «Working with RTTI - RAD Studio» (en anglès). docwiki.embarcadero.com. [Consulta: 6 juny 2021].
- ↑ English, John. «Chapter 15». A: Ada 95: The Craft of Object-Oriented Programming (en anglès), 2002-02-22.
- ↑ «Avoiding RTTI, and support for -fno-rtti in Arm Compiler 6» (en anglès). Arm Developer. [Consulta: 13 juliol 2021].