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