dynamic_cast Operator

The expression dynamic_cast<type-id>( expression ) converts the operand expression to an object of type type-id. The type-id must be a pointer or a reference to a previously defined class type or a “pointer to void”. The type of expression must be a pointer if type-id is a pointer, or an l-value if type-id is a reference.

See static_cast for an explanation of the difference between static and dynamic casting conversions, and when it is appropriate to use each.

dynamic_cast < type-id > ( expression )

If type-id is a pointer to an unambiguous accessible direct or indirect base class of expression, a pointer to the unique subobject of type type-id is the result. For example:

class B { ... };
class C : public B { ... };
class D : public C { ... };

void f(D* pd)
{
  C* pc = dynamic_cast<C*>(pd);  // ok: C is a direct base class
                      // pc points to C subobject of pd

  B* pb = dynamic_cast<B*>(pd);  // ok: B is an indirect base class
                      // pb points to B subobject of pd
  ...
}

This type of conversion is called an “upcast” because it moves a pointer up a class hierarchy, from a derived class to a class it is derived from. An upcast is an implicit conversion.

If type-id is void*, a run-time check is made to determine the actual type of expression. The result is a pointer to the complete object pointed to by expression. For example:

class A { ... };

class B { ... };

void f()
{
  A* pa = new A;
  B* pb = new B;
  void* pv = dynamic_cast<void*>(pa);
  // pv now points to an object of type A
  ...
  pv = dynamic_cast<void*>(pb);
  // pv now points to an object of type B
}

If type-id is not void*, a run-time check is made to see if the object pointed to by expression can be converted to the type pointed to by type-id.

If the type of expression is a base class of the type of type-id, a run-time check is made to see if expression actually points to a complete object of the type of type-id. If this is true, the result is a pointer to a complete object of the type of type-id. For example:

class B { ... };
class D : public B { ... };

void f()
{
  B* pb = new D;              // unclear but ok
  B* pb2 = new B;

  D* pd = dynamic_cast<D*>(pb);    // ok: pb actually points to a D
  ...
  D* pd2 = dynamic_cast<D*>(pb2);  //error: pb2 points to a B, not a D
                        // pd2 == NULL
  ...
}

This type of conversion is called a “downcast” because it moves a pointer down a class hierarchy, from a given class to a class derived from it.

In cases of multiple inheritance, possibilities for ambiguity are introduced. Consider the class hierarchy shown in Figure 4.5.

Figure 4.5   Class Hierarchy Showing Multiple Inheritance

A pointer to an object of type D can be safely cast to B or C. However, if D is cast to point to an A object, which instance of A would result? This would result in an ambiguous casting error. To get around this problem, you can perform two unambiguous casts. For example:

void f()
{
  D* pd = new D;
  A* pa = dynamic_cast<A*>(pd);    // error: ambiguous
  B* pb = dynamic_cast<B*>(pd);    // first cast to B
  A* pa2 = dynamic_cast<A*>(pb);  // ok: unambiguous
}

Further ambiguities can be introduced when you use virtual base classes. Consider the class hierarchy shown in Figure 4.6.

Figure 4.6   Class Hierarchy Showing Virtual Base Classes

In this hierarchy, A is a virtual base class. See Virtual Base Classes for the definition of a virtual base class. Given an instance of class E and a pointer to the A subobject, a dynamic_cast to a pointer to B will fail due to ambiguity. You must first cast back to the complete E object, then work your way back up the hierarchy, in an unambiguous manner, to reach the correct B object.

Consider the class hierarchy shown in Figure 4.7.

Figure 4.7   Class Hierarchy Showing Duplicate Base Classes

Given an object of type E and a pointer to the D subobject, to navigate from the D subobject to the left-most A subobject, three conversions can be made. You can perform a dynamic_cast conversion from the D pointer to an E pointer, then a conversion (either dynamic_cast or an implicit conversion) from E to B, and finally an implicit conversion from B to A. For example:

void f(D* pd)
{
  E* pe = dynamic_cast<E*>(pd);
  B* pb = pe;    // upcast, implicit conversion
  A* pa = pb;    // upcast, implicit conversion
}

The dynamic_cast operator can also be used to perform a “cross cast.” Using the same class hierarchy, it is possible to cast a pointer, for example, from the B subobject to the D subobject, as long as the complete object is of type E.

Considering cross casts, it is actually possible to do the conversion from a pointer to D to a pointer to the left-most A subobject in just two steps. You can perform a cross cast from D to B, then an implicit conversion from B to A. For example:

void f(D* pd)
{
  B* pb = dynamic_cast<B*>(pd);    // cross cast
  A* pa = pb;            // upcast, implicit conversion
}

A null pointer value is converted to the null pointer value of the destination type by dynamic_cast.

When you use dynamic_cast < type-id > ( expression ), if expression cannot be safely converted to type type-id, the run-time check causes the cast to fail. For example:

class A { ... };

class B { ... };

void f()
{
  A* pa = new A;
  B* pb = dynamic_cast<B*>(pa);    // fails, not safe;
                        // B not derived from A
  ...
}

The value of a failed cast to pointer type is the null pointer. A failed cast to reference type throws a bad_cast Exception.