Share via


In C++, if a class is derived from a base class containing one or more virtual functions, a pointer to that base class type can be used to call virtual functions in the derived class object. A class containing virtual functions is sometimes called a "polymorphic class."

Diagram of a class hierarchy where C derives from B, which derives from A.
Class hierarchy

An object of type C can be visualized as follows:

Diagram of Class C with subobjects B and A.
Class C with subobjects B and A

Given an instance of class C, there's a B subobject and an A subobject. The instance of C, including the A and B subobjects, is the "complete object."

Because a derived class completely contains the definitions of all the base classes from which it's derived, it's safe to cast a pointer to any of its base classes (also called an upcast). Given a pointer to a base class, it may be safe to cast the pointer to an instance of a derived class (also called a downcast).

Using run-time type information, it's possible to check whether a pointer actually points to a complete object and can be safely cast to point to another object in its hierarchy. The dynamic_cast operator performs a run-time check to ensure that the operation is safe. It's better to design your class hierarchy so that you can use virtual functions to avoid the need for downcasting. However, if you must downcast, use dynamic_cast to ensure that the operation is safe.

For conversion of nonpolymorphic types, you can use the static_cast operator (this topic explains the difference between static and dynamic casting conversions, and when it's appropriate to use each).

The following example demonstrates the use of dynamic_cast and static_cast:

#include <iostream>

class Base {
    virtual void print() { std::cout << "Base\n"; }

class Derived1 : public Base {
    void print() override { std::cout << "Derived1\n"; }

class Derived2 : public Base {
    void print() override { std::cout << "Derived2\n"; }

class MostDerived : public Derived1, public Derived2 {
    void print() override { std::cout << "MostDerived\n"; }

int main() {
    MostDerived md;
    Base* b1 = static_cast<Derived1*>(&md); // Upcast to Derived1 is safe
    Base* b2 = static_cast<Derived2*>(&md); // Upcast to Derived2 is safe

    // Downcast to MostDerived is ambiguous and unsafe
    // MostDerived* md1 = static_cast<MostDerived*>(b1); // This won't compile
    // MostDerived* md2 = static_cast<MostDerived*>(b2); // This won't compile

    // Correct way to downcast in this situation
    MostDerived* md1 = dynamic_cast<MostDerived*>(b1); // This is safe
    MostDerived* md2 = dynamic_cast<MostDerived*>(b2); // This is safe

    md1->print(); // Prints "MostDerived"
    md2->print(); // Prints "MostDerived"

    return 0;

This section covers the following topics:

See also