When casting down or across the hierarchy, the hierarchy must be polymorphic (have virtual functions). The result is checked at runtime.
The conversion from v to T is not always possible when casting down or across a hierarchy. For example, the attempted conversion might be ambiguous, T might be inaccessible, or v might not point (or refer) to an object of the necessary type. If the runtime check fails and T is a pointer type, the value of the cast expression is a null pointer of type T. If T is a reference type, nothing is returned (there are no null references in C++), and the standard exception std::bad_cast is thrown.
When you assume the following declarations:
class A { public: virtual void f( ); };
class B { public: virtual void g( ); };
class AB : public virtual A, private B { };
The following function succeeds:
void simple_dynamic_casts( )
{
AB ab;
B* bp = (B*)&ab; // cast needed to break protection
A* ap = &ab; // public derivation, no cast needed
AB& abr = dynamic_cast<AB&>(*bp); // succeeds
ap = dynamic_cast<A*>(bp); assert( ap != NULL );
bp = dynamic_cast<B*>(ap); assert( bp == NULL );
ap = dynamic_cast<A*>(&abr); assert( ap != NULL );
bp = dynamic_cast<B*>(&abr); assert( bp == NULL );
}
In the presence of virtual inheritance and multiple inheritance of a single base class, the actual dynamic cast must be able to identify a unique match. If the match is not unique, the cast fails. For example, given the additional class definitions:
class AB_B : public AB, public B { };
class AB_B__AB : public AB_B, public AB { };
The following function succeeds:
void complex_dynamic_casts( )
{
AB_B__AB ab_b__ab;
A*ap = &ab_b__ab;
// okay: finds unique A statically
AB*abp = dynamic_cast<AB*>(ap);
// fails: ambiguous
assert( abp == NULL );
// STATIC ERROR: AB_B* ab_bp = (AB_B*)ap;
// not a dynamic cast
AB_B*ab_bp = dynamic_cast<AB_B*>(ap);
// dynamic one is okay
assert( ab_bp != NULL );
}
The null-pointer error return of dynamic_cast is useful as a condition between two bodies of code--one to handle the cast if the type guess is correct, and one if it is not.
void using_dynamic_cast( A* ap )
{
if ( AB *abp = dynamic_cast<AB*>(ap) )
{ // abp is non-null,
// so ap was a pointer to an AB object
// go ahead and use abp
process_AB( abp ); }
else
{ // abp is null,
// so ap was NOT a pointer to an AB object
// do not use abp
process_not_AB( ap );
}
}
In compatibility mode (--compat=4), if runtime type information has not been enabled with the --features=rtti compiler option, the compiler converts dynamic_cast to static_cast and issues a warning. See Chapter 5.
If exceptions have been disabled, the compiler converts dynamic_cast<T&> to static_cast<T&> and issues a warning. The dynamic cast to a reference might require an exception in normal circumstances. See Chapter 4.
Dynamic cast is necessarily slower than an appropriate design pattern, such as conversion by virtual functions. See Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Addison Wesley, 1994.