← Back to C++ Course | Chapter 10: Polymorphism & Abstraction | Lesson 11 of 11

C++ RTTI

What is RTTI?

RTTI, or Run-Time Type Information, is the mechanism C++ provides for determining the exact, actual type of an object while the program is running, rather than relying only on the static type known at compile time.

Example: What is RTTI?

cpp
#include <iostream>
#include <typeinfo>

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

class Dog : public Animal {};

int main() {
	Animal *a = new Dog();
	std::cout << typeid(*a).name() << std::endl;
	delete a;
	return 0;
}

The typeid Operator

The typeid operator returns an object representing the real runtime type of an expression, which you can compare against another typeid result or use to print a human-readable (if compiler-specific) name of the class involved.

Example: The typeid Operator

cpp
#include <iostream>
#include <typeinfo>

int main() {
	int x = 5;
	double y = 3.14;
	std::cout << typeid(x).name() << " " << typeid(y).name() << std::endl;
	return 0;
}

Dynamic Cast on Pointers

The dynamic_cast operator safely converts a base class pointer into a derived class pointer, checking at runtime whether the object actually is of that derived type — if the cast isn't valid, it returns nullptr instead of producing an invalid pointer.

Example: Dynamic Cast on Pointers

cpp
#include <iostream>

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

class Dog : public Animal {
public:
	void bark() { std::cout << "Woof" << std::endl; }
};

int main() {
	Animal *a = new Dog();
	Dog *d = dynamic_cast<Dog *>(a);
	if (d != nullptr) d->bark();
	delete a;
	return 0;
}

Dynamic Cast on References

dynamic_cast also works on references, but since a reference can never be null, an invalid cast on a reference throws a std::bad_cast exception instead of silently returning a null value, which you're expected to catch if the cast might fail.

Example: Dynamic Cast on References

cpp
#include <iostream>

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

class Dog : public Animal {
public:
	void bark() { std::cout << "Woof" << std::endl; }
};

int main() {
	Dog realDog;
	Animal &a = realDog;
	try {
		Dog &d = dynamic_cast<Dog &>(a);
		d.bark();
	} catch (std::bad_cast &e) {
		std::cout << "Invalid cast" << std::endl;
	}
	return 0;
}

Best Practices with RTTI

RTTI checks carry a small but real runtime cost, so where possible it's preferable to design your class hierarchy around ordinary virtual function polymorphism, reserving RTTI for the specific cases — like certain plugin or serialization systems — where you genuinely need to inspect a type at runtime.

Example: Best Practices with RTTI

cpp
#include <iostream>

class Animal {
public:
	virtual void speak() { std::cout << "..." << std::endl; }
};

class Dog : public Animal {
public:
	void speak() override { std::cout << "Woof" << std::endl; }
};

int main() {
	Animal *a = new Dog();
	a->speak();
	delete a;
	return 0;
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.