Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Data Types  ›  Capstone Project

RTTI — Asking a Type at Run Time

RTTI 12 minRun-time type information lets code holding a base-class pointer or reference discover the real derived type of a polymorphic object, using dynamic_cast and typeid.

RTTI — Asking a Type at Run Time

Rocket Run keeps every enemy in one list of Enemy* pointers: drones, asteroids and the occasional boss. When the player lands a hit, the boss must move to its next phase, but a drone has no phases. The code holds a plain Enemy*. How can it find out what the object really is? That is what run-time type information, or RTTI, is for.

The rule

RTTI lets a base pointer ask which derived type it really points to.

A derived class is a more specific kind of its base class:

struct Enemy {
    virtual ~Enemy() = default;   // virtual: Enemy is now polymorphic
    int health = 10;
};
struct Boss  : Enemy { int phase = 1; };
struct Drone : Enemy {};

RTTI works only for polymorphic classes: those with at least one virtual function. The virtual destructor above is enough. With that in place you have two tools:

dynamic_cast converts to the derived type if the object really is one:

void onHit(Enemy* enemy) {
    if (auto* boss = dynamic_cast<Boss*>(enemy)) {
        ++boss->phase;          // only for bosses
    }
}

With a pointer, a failed cast returns nullptr. With a reference, dynamic_cast<Boss&>(e), a failure throws std::bad_cast, since there is no null reference.

typeid (header <typeinfo>) compares exact types: typeid(*enemy) == typeid(Boss). Its .name() text is implementation-defined; GCC, for instance, prints a mangled name, so use it only for debugging.

The shortcut

Before reaching for RTTI, ask: "Could the object answer this itself?" If every enemy should react to a hit in its own way, give Enemy a virtual void onHit() and let each class override it. Use dynamic_cast for the rare case where one piece of code truly needs the concrete type.

A hit on a DroneStep 1 of 4
  1. What the code holds

    Enemy* enemy points at a Drone object.

The trap is forgetting virtual. Without it, typeid(*enemy) reports the static type Enemy, and dynamic_cast from Enemy* down to Boss* will not even compile.

Drills

Answer fast — trust the rule.

quick drill

enemy points at a Drone. What does dynamic_cast<Boss*>(enemy) return?

quick drill

What must Enemy have for RTTI to see an object's real type?

quick drill

enemy points at a Boss and Enemy is polymorphic. What is typeid(*enemy) == typeid(Boss)?

quick drill

What happens when dynamic_cast<Boss&>(someEnemy) fails?

quick drill

Is the text from typeid(x).name() the same on every compiler?

Remember

  • RTTI lets a base pointer ask which derived type it really points to.
  • Shortcut: first ask whether a virtual function could answer instead.
  • Trap: no virtual, no RTTI; a failed pointer cast is nullptr, a failed reference cast throws.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainIs this enemy the boss?

Rocket Run keeps all enemies as Enemy*. When the player hits one, the game must check whether it is a Boss to update its phase. Explain how dynamic_cast answers this, what it returns when the enemy is not a Boss, what Enemy needs for it to work, and when a virtual function would be the better design.