C++ Programming Guide

Dynamic Casts

A pointer (or reference) to a class can actually point (refer) to any class derived from that class. Occasionally, it may be desirable to obtain a pointer to the fully derived class, or to some other subobject of the complete object. The dynamic cast provides this facility.

The dynamic type cast converts a pointer (or reference) to one class T1 into a pointer (reference) to another class T2. T1 and T2 must be part of the same hierarchy, the classes must be accessible (via public derivation), and the conversion must not be ambiguous. In addition, unless the conversion is from a derived class to one of its base classes, the smallest part of the hierarchy enclosing both T1 and T2 must be polymorphic (have at least one virtual function).

In the expression dynamic_cast<T>(v), v is the expression to be cast, and T is the type to which it should be cast. T must be a pointer or reference to a complete class type (one for which a definition is visible), or a pointer to cv void, where cv is an empty string, const, volatile, or const volatile.

Casting Up the Hierarchy

When casting up the hierarchy, if T points (or refers) to a base class of the type pointed (referred) to by v, the conversion is equivalent to static_cast<T>(v).

Casting to void*

If T is void*, the result is a pointer to the complete object. That is, v might point to one of the base classes of some complete object. In that case, the result of dynamic_cast<void*>(v) is the same as if you converted v down the hierarchy to the type of the complete object (whatever that is) and then to void*.

When casting to void*, the hierarchy must be polymorphic (have virtual functions). The result is checked at runtime.

Casting Down or Across the Hierarchy

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.