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.
Syntax
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.