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.