RunTime Type Information or RunTime Type Identification, or just RTTI, is a useful feature in C++ language. As its name suggests, this facility gives you the ability to query type information at runtime.
dynamic_cast<>
typeid()
Those are the main tools to achieve RTTI. Some of you may frown upon this RTTI thing because it seems to have a bad reputation out there, and there is a good reason for that. Generally you want to stay away from this feature because static typing is much safer than dynamic typing thanks to the compiler, and it gives you runtime overheads as well. So why is it useful?
Walking around the Inheritance Graph
Generally we use virtual inheritance and polymorphism because we only care about the interface but not the exact implementations. However, some derived classes may have specific method that doesn’t fit into the interface in any way. Although it is possible to add another virtual function to the base class and all its derived classes and let them provide empty implementations. But doesn’t that sounds awkward when you tell every Person class to program() when a Programmer class has to? It might be more reasonable to recover the true type (not exactly right with dynamic_cast<>, I’ll talk about it later) of a polymorphic type and call the class’s unique function as needed.
dynamic_cast<>
is your first choice to achieve this. Consider the following codes,
1 | class Base1 |
As is quite clear in the codes and comments, you can use dynamic_cast<>
to walk around the inheritance graph get to the specific class you need, as long as virtual inheritance is used. The name upcast, downcast, and crosscast come from the tradition to draw base class on top of the derived in an inheritance graph.
Querying the Exact Type
Remember earlier I said that dynamic_cast<>
isn’t really about recovering the true type of a polymorphic pointer. Let’s say we have another class down the inheritance graph,
1 | class FurtherDerived : public Derived |
Bjarne Stroustrup has made this quite clear in TCPL,
From a design perspective, dynamic_cast can be seen as a mechanism for asking an object if it provides a given interface
As long as the class provides the requested interface, dynamic_cast<>
will work. In other words it works for all derived classes down the road. So how do we find out the exact type of an object? It’s typeid()
to the rescue.
1 | typeid(*pb1) == typeid(FurtherDerived); // true |
The return type of typeid()
is std::type_info
which has some other useful functions like hashing and name string. Keep in mind that typid()
and dynamic_cast<>
are designed for different tasks so you shouldn’t misuse both.
Alternatives
You could almost always redesign the inheritance relationships and use virtual functions to do dynamic dispatching. But do know that you have the right tools at hands and don’t hesitate to use them when needed.