|C H A P T E R 9|
This chapter discusses the newer cast operators in the C++ standard: const_cast, reinterpret_cast, static_cast, and dynamic_cast. A cast converts an object or value from one type to another.
These cast operations provide finer control than previous cast operations. The dynamic_cast<> operator provides a way to check the actual type of a pointer to a polymorphic class. You can search with a text editor for all new-style casts (search for _cast), whereas finding old-style casts required syntactic analysis.
Otherwise, the new casts all perform a subset of the casts allowed by the classic cast notation. For example, const_cast<int*>(v) could be written (int*)v. The new casts simply categorize the variety of operations available to express your intent more clearly and allow the compiler to provide better checking.
The cast operators are always enabled. They cannot be disabled.
The expression const_cast<T>(v) can be used to change the const or volatile qualifiers of pointers or references. (Among new-style casts, only const_cast<> can remove const qualifiers.) T must be a pointer, reference, or pointer-to-member type.
The expression reinterpret_cast<T>(v)changes the interpretation of the value of the expression v. It can be used to convert between pointer and integer types, between unrelated pointer types, between pointer-to-member types, and between pointer-to-function types.
Usage of the reinterpret_cast operator can have undefined or implementation-dependent results. The following points describe the only ensured behavior:
The expression static_cast<T>(v) converts the value of the expression v to type T. It can be used for any type conversion that is allowed implicitly. In addition, any value can be cast to void, and any implicit conversion can be reversed if that cast would be legal as an old-style cast.
The static_cast operator cannot be used to cast away const. You can use static_cast to cast "down" a hierarchy (from a base to a derived pointer or reference), but the conversion is not checked; the result might not be usable. A static_cast cannot be used to cast down from a virtual base class.
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.
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).
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).
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:
whereas this example fails because base class B is inaccessible.
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:
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.
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 Chapter 8.
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).