Run-time type information (RTTI) enables determining object type during runtime.
This is enabled by the following language features:
- dynamic_cast
converts pointers and references to objects of polymorphic classes - typeid
identify type of an object at runtime - std::type_info
store information of objects type returned by typeid.
This post only talks about dynamic_cast.
dynamic_cast
“The need for dynamic_cast generally arises because you want to perform derived class operation on a derived class object, but you have only a pointer or reference-to-base” said Scott Meyers in his book “Effective C++”.
Full description on cppreference.
Basic usages:
dynamic_cast is normaly used when you dont know what type the object is, and then you start trying out its type by casting.
There are 2 variants for using dynamic_cast: casting a pointer and casting a reference.
Having a pointer to an object B of a base class Base try to (down) cast to a derived class Derived:
returns nullptr on error, otherwise valid pointer if cast is successfull.
Having a reference to an object B of a base class Base try to (down) cast to a derived class Derived:
throws std::bad_cast on error, otherwise returns valid reference if cast is successfull.
class Base { public: virtual ~Base() = default; // Base needs to be polymorphic in order to use runtime-checked dynamic_cast ... }; class Derived : public Base {}; void useDerivedPointer(Base* base) { auto derived = dynamic_cast<Derived*>(base); if (derived) { // cast OK - use derived } else { // cast NOK - base is not an instance of Derived } } void useDerivedReference(Base& base) { try { auto derived = dynamic_cast<Derived&>(base); // cast OK } catch (const std::bad_cast& e) { // cast NOK } } int main() { useDerivedPointer(new Derived()); // cast OK useDerivedPointer(new Base()); // cast NOK useDerivedReference(*(new Derived())); // cast OK useDerivedReference(*(new Base())); // cast NOK }
It usually raises from having different public interfaces. One solution to eliminate this scenario is to replace the different interfaces with one unified interface and using e.g. runtime dispatching of function calls instead of casting the objects.
dynamic_cast is normaly considered bad practice because it normally means complex inheritance hierarchies and bad API’s and should be avoided if possible. It also can have perfomance impacts in perfomance critical code, because as stated above: it does a runtime-type check, that means, the compiler will generate some code for it which will be executed at runtime, as can be seen in the image below: