In computer programming, run-time type information or run-time type identification (RTTI)[1] is a feature of the C++ programming language that exposes information about an object's data type at runtime. Run-time type information can apply to simple data types, such as integers and characters, or to generic types. This is a C++ specialization of a more general concept called type introspection. Similar mechanisms are also known in other programming languages, such as Object Pascal (Delphi).
In the original C++ design, Bjarne Stroustrup did not include run-time type information, because he thought this mechanism was often misused.[2]
Overview
In C++, RTTI can be used to do safe typecasts, using the dynamic_cast<> operator, and to manipulate type information at runtime, using the typeid operator and std::type_info class.
RTTI is available only for classes that are polymorphic, which means they have at least one virtual method. In practice, this is not a limitation because base classes must have a virtual destructor to allow objects of derived classes to perform proper cleanup if they are deleted from a base pointer.
RTTI is optional with some compilers; the programmer can choose at compile time whether to include the functionality. There may be a resource cost to making RTTI available even if a program does not use it.
typeid
The typeid keyword is used to determine the class of an object at run time. It returns a reference to std::type_info object, which exists until the end of the program.[3] The use of typeid, in a non-polymorphic context, is often preferred over dynamic_cast<class_type> in situations where just the class information is needed, because typeid is always a constant-time procedure, whereas dynamic_cast may need to traverse the class derivation lattice of its argument at runtime. Some aspects of the returned object are implementation-defined, such as std::type_info::name, and cannot be relied on across compilers to be consistent.
Objects of class std::bad_typeid are thrown when the expression for typeid is the result of applying the unary * operator on a null pointer. Whether an exception is thrown for other null reference arguments is implementation-dependent. In other words, for the exception to be guaranteed, the expression must take the form typeid(*p) where p is any expression resulting in a null pointer.
Example
#include <iostream> #include <typeinfo> 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::cout << typeid(person).name << std::endl; // Person (statically known at compile-time). std::cout << typeid(employee).name << std::endl; // Employee (statically known at compile-time). std::cout << typeid(ptr).name << std::endl; // Person* (statically known at compile-time). std::cout << typeid(*ptr).name << std::endl; // Employee (looked up dynamically at run-time // because it is the dereference of a // pointer to a polymorphic class). std::cout << typeid(ref).name << std::endl; // Employee (references can also be polymorphic) Person* p = nullptr; try { typeid(*p); // Not undefined behavior; throws std::bad_typeid. } catch (...) { } 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. } Output (exact output varies by system and compiler):
Person Employee Person* Employee Employee
dynamic_cast and Java cast
The dynamic_cast operator in C++ is used for downcasting a reference or pointer to a more specific type in the class hierarchy. Unlike the static_cast, the target of the dynamic_cast must be a pointer or reference to class. Unlike static_cast and C-style typecast (where type check is made during compilation), a type safety check is performed at runtime. If the types are not compatible, an exception will be thrown (when dealing with references) or a null pointer will be returned (when dealing with pointers).
A Java typecast behaves similarly; if the object being cast is not actually an instance of the target type, and cannot be converted to one by a language-defined method, an instance of java.lang.ClassCastException will be thrown.[4]
Example
Suppose some function takes an object of type A as its argument, and wishes to perform some additional operation if the object passed is an instance of B, a subclass of A. This can be accomplished using dynamic_cast as follows.
#include <array> #include <iostream> #include <memory> #include <typeinfo> using namespace std; class A { public: // Since RTTI is included in the virtual method table there should be at // least one virtual function. virtual ~A = default; void MethodSpecificToA { cout << "Method specific for A was invoked" << endl; } }; class B: public A { public: void MethodSpecificToB { cout << "Method specific for B was invoked" << endl; } }; void MyFunction(A& my_a) { try { // Cast will be successful only for B type objects. B& my_b = dynamic_cast<B&>(my_a); my_b.MethodSpecificToB; } catch (const bad_cast& e) { cerr << " Exception " << e.what << " thrown." << endl; cerr << " Object is not of type B" << endl; } } int main { array<unique_ptr<A>, 3> array_of_a; // Array of pointers to base class A. array_of_a[0] = make_unique<B>; // Pointer to B object. array_of_a[1] = make_unique<B>; // Pointer to B object. array_of_a[2] = make_unique<A>; // Pointer to A object. for (int i = 0; i < 3; ++i) MyFunction(*array_of_a[i]); } Console output:
Method specific for B was invoked Method specific for B was invoked Exception std::bad_cast thrown. Object is not of type B
A similar version of MyFunction can be written with pointers instead of references:
void MyFunction(A* my_a) { B* my_b = dynamic_cast<B*>(my_a); if (my_b != nullptr) my_b->methodSpecificToB; else std::cerr << " Object is not B type" << std::endl; } See also
- Type inference
- Type introspection
- typeof
- Reflection (computer science)
- Template (C++)
References
- ^ Sun Microsystems (2000). "Runtime Type Identification". C++ Programming Guide. Oracle. Retrieved 16 April 2015.
- ^ Bjarne Stroustrup (March 1993). "A History of C++: 1979—1991" (PDF). Bjarne Stroustrup. p. 50. Retrieved 2009-05-18.
- ^ C++ standard (ISO/IEC14882) section 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
- ^ http://docs.oracle.com/javase/8/docs/api/java/lang/ClassCastException.html