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.
For example, this example of public derivation succeeds:
#include <assert.h> #include <stddef.h> // for NULL class A {public: virtual void f();}; class B {public: virtual void g();}; class AB: public virtual A, public B {}; void simple_dynamic_casts() { AB ab; B* bp = &ab; // no casts needed A* ap = &ab; 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); } |
whereas this example fails because base class B is inaccessible.
#include <assert.h> #include <stddef.h> // for NULL #include <typeinfo> class A {public: virtual void f() {}}; class B {public: virtual void g() {}}; class AB: public virtual A, private B {}; void attempted_casts() { AB ab; B* bp = (B*)&ab; // C-style cast needed to break protection A* ap = dynamic_cast<A*>(bp); // fails, B is inaccessible assert(ap == NULL); try { AB& abr = dynamic_cast<AB&>(*bp); // fails, B is inaccessible } catch(const std::bad_cast&) { return; // failed reference cast caught here } assert(0); // should not get here } |
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 {}; |
Example:
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.
If exceptions have been disabled, the compiler converts dynamic_cast<T&> to static_cast<T&> and issues a warning. (A dynamic_cast to a reference type requires an exception to be thrown if the conversion is found at run time to be invalid.) For information about exceptions, see 7.5.3 Troubleshooting a Problematic Search.
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).