From e6c52ae0f4ea88516503715a675ed9c1d56b88df Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 15 Sep 2003 16:30:22 +0000 Subject: [PATCH] Improved justification for polymorphic_cast. [SVN r20068] --- cast.htm | 258 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 155 insertions(+), 103 deletions(-) diff --git a/cast.htm b/cast.htm index 9122c01..ce596a5 100644 --- a/cast.htm +++ b/cast.htm @@ -1,64 +1,85 @@ + + + + + - - - - -Header boost/cast.hpp Documentation - + Header boost/cast.hpp Documentation + - + +

c++boost.gif (8819 bytes)Header boost/cast.hpp

-

c++boost.gif (8819 bytes)Header -boost/cast.hpp

+

Cast Functions

-

Cast Functions

+

The header boost/cast.hpp provides + polymorphic_cast, polymorphic_downcast, and numeric_cast function templates designed to + complement the C++ built-in casts.

-

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.

-

The program cast_test.cpp can be used to -verify these function templates work as expected.

-

Polymorphic casts

-

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 polymorphic_cast template performs a dynamic_cast, -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.

-

polymorphic_cast and polymorphic_downcast synopsis

-
-
namespace boost {
+    

Polymorphic casts

+ +

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.

+ +

polymorphic_cast and polymorphic_downcast synopsis

+ +
+
+namespace boost {
 
 template <class Derived, class Base>
 inline Derived polymorphic_cast(Base* x);
@@ -70,11 +91,15 @@ inline Derived polymorphic_downcast(Base* x);
 // Effects: assert( dynamic_cast<Derived>(x) == x );
 // Returns: static_cast<Derived>(x)
 
-}
-
-

polymorphic_downcast example

-
-
#include <boost/cast.hpp>
+}
+
+
+ +

polymorphic_downcast example

+ +
+
+#include <boost/cast.hpp>
 ...
 class Fruit { public: virtual ~Fruit(){}; ... };
 class Banana : public Fruit { ... };
@@ -82,26 +107,40 @@ 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);
-  ...
-
-

numeric_cast

-

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

numeric_cast synopsis

-
-
namespace boost {
+  ...
+
+
+ +

numeric_cast

+ +

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.
  • +
+
+ +

numeric_cast synopsis

+ +
+
+namespace boost {
 
 class bad_numeric_cast : public std::bad_cast {...};
 
@@ -112,11 +151,15 @@ template<typename Target, typename Source>
     //          overflow, as determined by std::numeric_limits
     // Returns: static_cast<Target>(arg)
 
-}
-
-

numeric_cast example

-
-
#include <boost/cast.hpp>
+}
+
+
+ +

numeric_cast example

+ +
+
+#include <boost/cast.hpp>
 using namespace boost::cast;
 
 void ariane(double vx)
@@ -124,27 +167,36 @@ void ariane(double vx)
     ...
     unsigned short dx = numeric_cast<unsigned short>(vx);
     ...
-}
-
-

numeric_cast rationale

-

The form of the throws condition is specified so that != is not a required -operation.

-

History

-

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.

+} +
+
- +

numeric_cast rationale

+

The form of the throws condition is specified so that != is not a + required operation.

+ +

History

+ +

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.

+ +