In computer programming, run-time type information or run-time type identification (RTTI) is a feature of some programming languages (such as C++, Object Pascal, and Ada) that exposes information about an object's data type at runtime. Run-time type information may be available for all types or only to types that explicitly have it (as is the case with Ada). Run-time type information is a specialization of a more general concept called type introspection.

In the original C++ design, Bjarne Stroustrup did not include run-time type information, because he thought this mechanism was often misused.

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. In Object Pascal, RTTI can be used to perform safe type casts with the as operator, test the class to which an object belongs with the is operator, and manipulate type information at run time with classes contained in the RTTI unit (i.e. classes: TRttiContext, TRttiInstanceType, etc.). In Ada, objects of tagged types also store a type tag, which permits the identification of the type of these object at runtime. The in operator can be used to test, at runtime, if an object is of a specific type and may be safely converted to it.

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.

Some compilers have flags to disable RTTI. Using these flags may reduce the overall size of the application, making them especially useful when targeting systems with a limited amount of memory.

C++ – 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.  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

C++ – 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.

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;
}

Delphi / Object Pascal 
In Object Pascal, the operator is is used to check the type of a class at run time. It tests the belonging of an object to a given class, including classes of individual ancestors present in the inheritance hierarchy tree (e.g. Button1 is a TButton class that has ancestors: TWinControl → TControl → TComponent → TPersistent → TObject, where the latter is the ancestor of all classes). The operator as is used when an object needs to be treated at run time as if it belonged to an ancestor class.

The RTTI unit is used to manipulate object type information at run time. This unit contains a set of classes that allow you to: get information about an object's class and its ancestors, properties, methods and events, change property values and call methods. The following example shows the use of the RTTI module to obtain information about the class to which an object belongs, creating it, and to call its method. The example assumes that the TSubject class has been declared in a unit named SubjectUnit.uses
  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;

See also
 Type inference
 Type introspection
 typeof
 Reflection (computer science)
 Template (C++)

References

External links
 dynamic_cast operator at IBM Mac OS X Compilers
 dynamic_cast operator at MSDN

Articles with example C++ code
C++
Class (computer programming)
Data types
런타임 타입 정보(RTTI, Run-Time Type Information 또는 Run-Time Type Identification)는 런타임 시 객체의 자료형에 관한 정보를 드러내는 C++ 메커니즘을 가리킨다. RTTI는 간단한 정수나 문자와 같은 자료형 또는 제네릭 타입에 적용할 수 있다. 이것은 타입 인트로스펙션이라고 부르는 더 일반적인 개념의 C++ 특수화이다. 델파이 (오브젝트 파스칼)같은 다른 프로그래밍 언어들에서도 비슷한 메카니즘이 존재한다.

원래 C++ 디자인에서, 비야네 스트롭스트룹은 이 메커니즘이 자주 오용된다고 생각했기 때문에,  RTTI를 포함시키지 않았다.

개요 
dynamic_cast<> 연산과  typeid 연산자가 C++에서 RTTI를 구성한다. C++ 런타임 타입 정보는 런타임시에 안전한 형 변환과 타입 조작의 수행을 허용한다. RTTI는 오직 다형적인 클래스들에서 사용가능한데, 이것은 적어도 하나의 가상 함수를 갖는다는 것을 의미한다. 실제로 이 점은 만약 이것들이 베이스 포인터에서 지워진 경우, 베이스 클래스들은 (반드시 상속받은 클래스들의 객체들이 적절한 클린업을 수행하게 하는) 가상 소멸자를 가져야 하기 때문에 한계라고 할 수 없다. RTTI는 어떤 컴파일러들에서는 선택사항이다; 프로그래머는 컴파일 시에 함수를 포함할 지를 선택할 수 있다. 프로그램은 이것을 사용하지 않더라도 RTTI를 사용가능하게 만들 리소스 비용이 존재할 것이다.

typeid 
typeid 키워드는 런타임 시에 객체의 클래스를 선택하는데 사용된다. 이것은 std::type_info 객체에 대한 참조를 반환하는데, 프로그램의 종료 시까지 존재하게 된다. 다형성이 사용되지 않은 문맥에서 단지 클래스 정보가 필요한 경우 typeid의 사용은 종종 dynamic_cast<class_type> 보다 선호된다. 왜냐하면 dynamic_cast가 반드시 런타임시에 이것의 인자의 클래스 상속 래티스를 순회해야하는 반면, typeid는 시상수 프로시저이기 때문이다. 반환된 객체의 어떤 면들은 std::type_info::name() 처럼 구현 시에 정의되며, 모든 컴파일러들에서 일정하다고 할 수는 없다.

클래스 std::bad_typeid의 객체들은 널 포인터에서 typeid를 위한 표현이 unary * 연산자를 적용하는 것의 결과일 때 던져진다. 예외가 다른 널 참조 인자에 던져지든지 말든지는 구현에 종속적이다. 즉, p가 널 포인터를 야기하는 어느 표현일 때, 보장되어야 할 예외를 위해 표현은 반드시 typeid(*p) 형태를 취해야 한다.

예시 
#include <iostream>    // cout
#include <typeinfo>    // for 'typeid'

class Person {
public:
   virtual ~Person() {}
};

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& pRef = *p; // Undefined behavior: dereferencing null
   typeid(pRef);      // does not meet requirements to throw std::bad_typeid
                      // because the expression for typeid is not the result
                      // of applying the unary * operator
}결과 (시스템에 따라 정확한 결과는 다르다.):
 Person
 Employee
 Person*
 Employee
 Employee

dynamic_cast 와Java cast 
C++의  dynamic_cast 연산자는 클래스 계층에서 참조나 포인터를 더 구체적인 타입으로 다운캐스팅하는데 사용된다.  static_cast와 달리, dynamic_cast 의 대상은 반드시 클래스에 대한 포인터나 참조여야 한다. static_cast 와 C-스타일 타입캐스트(타입 검사가 컴파일 시에 이루어지는)와 달리, 타입 안전 검사는 런타임 시에 수행된다. 만약 타입들이 호환되지 않는다면, 예외가 던져지거나(참조를 다룰 때) 널 포인터가 반환될(포인터를 다룰 때) 것이다.

자바 타입캐스트도 비슷하게 동작한다; 만약 던져진 객체가 실제로 대상 타입의 인스턴스가 아니고, 인스턴스인 언어로 정의된 방식으로 변환되지 못한다면,  java.lang.ClassCastException 의 인스턴스가 던져질 것이다.

예시 
몇몇 함수가 타입 A의 객체를 인자로 받으며, 만약 전달받은 객체가 B의 인스턴스이고, A의 서브클래스라면, 몇몇 추가적인 연산을 수행하길 바란다고 가정하자. 이것은 다음과 같이 dynamic_cast 를 사용함으로써 달성될 수 있다.#include <typeinfo> // For std::bad_cast
#include <iostream> // For std::cout, std::err, std::endl etc.

class A {
public:
    // Since RTTI is included in the virtual method table there should be at least one virtual function.
    virtual ~A() { };
    void methodSpecificToA() { std::cout << "Method specific for A was invoked" << std::endl; };
};

class B : public A {
public:
    void methodSpecificToB() { std::cout << "Method specific for B was invoked" << std::endl; };
    virtual ~B() { };
};

void my_function(A& my_a)
{
    try {
        B& my_b = dynamic_cast<B&>(my_a); // cast will be successful only for B type objects.
        my_b.methodSpecificToB();
    }
    catch (const std::bad_cast& e) {
        std::cerr << "  Exception " << e.what() << " thrown." << std::endl;
        std::cerr << "  Object is not of type B" << std::endl;
    }
}

int main()
{
    A *arrayOfA[3];          // Array of pointers to base class (A)
    arrayOfA[0] = new B();   // Pointer to B object
    arrayOfA[1] = new B();   // Pointer to B object
    arrayOfA[2] = new A();   // Pointer to A object
    for (int i = 0; i < 3; i++) {
        my_function(*arrayOfA[i]);
        delete arrayOfA[i];  // delete object to prevent memory leak
    }
}콘솔 결과:
 Method specific for B was invoked
 Method specific for B was invoked
 Exception std::bad_cast thrown.
 Object is not of type B
my_function의 비슷한 버전이 참조 대신 포인터로 쓰여질 수 있다:void my_function(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;
}

같이 보기 
 반영 (컴퓨터 과학)

각주

외부 링크 
 dynamic_cast operator at IBM Mac OS X Compilers
 dynamic_cast operator at MSDN

C++
자료형