The header boost/cast.hpp provides polymorphic_cast, polymorphic_downcast, and numeric_cast function templates designed to complement the C++ built-in casts.
The program cast_test.cpp can be used to verify these function templates work as expected.
Pointers to polymorphic objects (objects of classes which define at least one virtual function) are sometimes downcast or crosscast. Downcasting means casting from a base class to a derived class. Crosscasting means casting across an inheritance hierarchy diagram, such as from one base to the other in a Y diagram hierarchy.
Such casts can be done with old-style casts, but this approach is never to be recommended. Old-style casts are sorely lacking in type safety, suffer poor readability, and are difficult to locate with search tools.
The C++ built-in static_cast can be used for efficiently downcasting pointers to polymorphic objects, but provides no error detection for the case where the pointer being cast actually points to the wrong derived class. The polymorphic_downcast template retains the efficiency of static_cast for non-debug compilations, but for debug compilations adds safety via an assert() that a dynamic_cast succeeds.
The C++ built-in dynamic_cast can be used for downcasts and
crosscasts of pointers to polymorphic objects, but error notification in
the form of a returned value of 0 is inconvenient to test, or worse yet,
easy to forget to test. The throwing form of dynamic_cast, which
works on references, can be used on pointers through the ugly expression
&dynamic_cast<T&>(*p)
, which causes undefined
behavior if p
is 0
. The polymorphic_cast
template performs a dynamic_cast on a pointer, and throws an
exception if the dynamic_cast returns 0.
A polymorphic_downcast is preferred when debug-mode tests will cover 100% of the object types possibly cast and when non-debug-mode efficiency is an issue. If these two conditions are not present, polymorphic_cast is preferred. It must also be used for crosscasts. It does an assert( dynamic_cast<Derived>(x) == x ) where x is the base pointer, ensuring that not only is a non-zero pointer returned, but also that it correct in the presence of multiple inheritance. Warning:: Because polymorphic_downcast uses assert(), it violates the one definition rule (ODR) if NDEBUG is inconsistently defined across translation units. [See ISO Std 3.2]
The C++ built-in dynamic_cast must be used to cast references rather than pointers. It is also the only cast that can be used to check whether a given interface is supported; in that case a return of 0 isn't an error condition.
namespace boost { template <class Derived, class Base> inline Derived polymorphic_cast(Base* x); // Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 ) // Returns: dynamic_cast<Derived>(x) template <class Derived, class Base> inline Derived polymorphic_downcast(Base* x); // Effects: assert( dynamic_cast<Derived>(x) == x ); // Returns: static_cast<Derived>(x) }
#include <boost/cast.hpp> ... class Fruit { public: virtual ~Fruit(){}; ... }; class Banana : public Fruit { ... }; ... void f( Fruit * fruit ) { // ... logic which leads us to believe it is a Banana Banana * banana = boost::polymorphic_downcast<Banana*>(fruit); ...
A static_cast or implicit conversion will not detect failure to preserve range for numeric casts. The numeric_cast function templates are similar to static_cast and certain (dubious) implicit conversions in this respect, except that they detect loss of numeric range. An exception is thrown when a runtime value-preservation check fails.
The requirements on the argument and result types are:
- Both argument and result types are CopyConstructible [ISO Std 20.1.3].
- Both argument and result types are Numeric, defined by
std::numeric_limits<>::is_specialized
being true.- The argument can be converted to the result type using static_cast.
namespace boost { class bad_numeric_cast : public std::bad_cast {...}; template<typename Target, typename Source> inline Target numeric_cast(Source arg); // Throws: bad_numeric_cast unless, in converting arg from Source to Target, // there is no loss of negative range, and no underflow, and no // overflow, as determined by std::numeric_limits // Returns: static_cast<Target>(arg) }
#include <boost/cast.hpp> using namespace boost::cast; void ariane(double vx) { ... unsigned short dx = numeric_cast<unsigned short>(vx); ... }
The form of the throws condition is specified so that != is not a required operation.
polymorphic_cast was suggested by Bjarne Stroustrup in "The C++
Programming Language".
polymorphic_downcast was contributed by Dave Abrahams.
numeric_cast was contributed by Kevlin Henney.
Revised 06 January, 2001
© Copyright boost.org 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.