Dynamic casting is used to downcast pointers or references to derived class to base class. Similar to static cast, dynamic casting is done using a dynamic_cast operator.

For example:

#include <iostream>
class Base
{
public:
    Base(int base_value)
    {
    }
 
    void baseFn()
    {
        std::cout << "Base function called." << std::endl;
    }
    virtual ~Base() = default;
};
 
class Derived : public Base
{
    int value;
 
public:
    Derived(int derived_value, int base_value)
        : value{derived_value}, Base(base_value)
    {
    }
    void derivedFn()
    {
        std::cout << "Derived function: " << value << '\n';
    }
};
 
Base *getObject(bool returnDerived = true)
{
    if (returnDerived)
    {
        return new Derived(1, 2);
    }
    else
    {
        return new Base(1);
    }
}
 
int main(int argc, char const *argv[])
{
    Base *ptr{getObject(false)};
 
    // ptr->derivedFn();
    Derived *derivedPtr = dynamic_cast<Derived *>(ptr);
 
    if (derivedPtr)
        derivedPtr->derivedFn();
    return 0;
}
 

This example shows casting the returned Base* pointer to Derived* pointer type. If dynamic_cast is unable to downcast from base to derived, it returns a null pointer that we can check before accessing the pointer.

dynamic_cast performs some checks if the casting is possible or not. This extra operations make dynamic casting slow and inefficient as compared to static_cast.

dynamic_cast vs static_cast

We could use static_cast but it does not provide any checks that dynamic_cast provides. For example, if static_cast a pointer of base type to derived type even if pointer points to the base object, the casting would be successful. If we try to access derived object members through the pointer, undefined things would happen (program crash).

For example:

Base b;
Base *ptr{b};
 
Derived*d_ptr{dynamic_cast<Derived*>(b)}; // it would fail and return nullptr
 
Derived*d_ptr{static_cast<Derived*>(b)}; // it would not fail but
 
d_ptr->derivedFn(); // it would crash the program

So, dynamic_cast returns a null pointer if casting from base to derived is not possible as pointer points to an object of base type. However, static_cast would not fail but accessing derived members through this pointer would crash the program.

dynamic_cast with references

Operation of dynamic_cast with references is analogous to pointers. The only difference is that when the dynamic casting fails, it throws std::bad_cast exception.

RTTI for dynamic_cast

Runtime type information is a mechanism by which C++ determines object type information at the execution time. dynamic_cast uses this mechanism for it to work. RTTI adds performance and space cost and thus most compilers allow us to disable RTTI for optimization. However, if you disable this then dynamic_cast would not work properly.

References

  1. https://www.learncpp.com/cpp-tutorial/dynamic-casting/
  2. https://learn.microsoft.com/en-us/cpp/cpp/run-time-type-information?view=msvc-170