Improved justification for polymorphic_cast.

[SVN r20068]
This commit is contained in:
Dave Abrahams
2003-09-15 16:30:22 +00:00
parent 13796f3f98
commit e6c52ae0f4

258
cast.htm
View File

@@ -1,64 +1,85 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html> <html>
<head>
<meta name="generator" content=
"HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
<meta http-equiv="Content-Type" content=
"text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<head> <title>Header boost/cast.hpp Documentation</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> </head>
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Header boost/cast.hpp Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000"> <body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align=
"middle" width="277" height="86">Header <a href=
"../../boost/cast.hpp">boost/cast.hpp</a></h1>
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="middle" width="277" height="86">Header <h2><a name="Cast Functions">Cast Functions</a></h2>
<a href="../../boost/cast.hpp">boost/cast.hpp</a></h1>
<h2><a name="Cast Functions">Cast Functions</a></h2> <p>The header <a href="../../boost/cast.hpp">boost/cast.hpp</a> provides
<a href="#Polymorphic_cast"><b>polymorphic_cast</b></a>, <a href=
"#Polymorphic_cast"><b>polymorphic_downcast</b></a>, and <a href=
"#numeric_cast"><b>numeric_cast</b></a> function templates designed to
complement the C++ built-in casts.</p>
<p>The header <a href="../../boost/cast.hpp">boost/cast.hpp</a> <p>The program <a href="cast_test.cpp">cast_test.cpp</a> can be used to
provides <a href="#Polymorphic_cast"><b>polymorphic_cast</b></a>, <a href="#Polymorphic_cast"><b>polymorphic_downcast</b></a>, verify these function templates work as expected.</p>
and <a href="#numeric_cast"><b>numeric_cast</b></a> function templates designed
to complement the C++ built-in casts.</p>
<p>The program <a href="cast_test.cpp">cast_test.cpp</a> can be used to <h3><a name="Polymorphic_cast">Polymorphic casts</a></h3>
verify these function templates work as expected.</p>
<h3><a name="Polymorphic_cast">Polymorphic casts</a></h3> <p>Pointers to polymorphic objects (objects of classes which define at
<p>Pointers to polymorphic objects (objects of classes which define at least one least one virtual function) are sometimes downcast or crosscast.
virtual function) are sometimes downcast or crosscast. Downcasting means Downcasting means casting from a base class to a derived class.
casting from a base class to a derived class. Crosscasting means casting Crosscasting means casting across an inheritance hierarchy diagram, such
across an inheritance hierarchy diagram, such as from one base to the other in a as from one base to the other in a <b>Y</b> diagram hierarchy.</p>
<b>Y</b> diagram hierarchy.</p>
<p>Such casts can be done with old-style casts, but this approach is never to be <p>Such casts can be done with old-style casts, but this approach is
recommended. Old-style casts are sorely lacking in type safety, suffer never to be recommended. Old-style casts are sorely lacking in type
poor readability, and are difficult to locate with search tools.</p> safety, suffer poor readability, and are difficult to locate with search
<p>The C++ built-in <b>static_cast</b> can be used for efficiently downcasting tools.</p>
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 <b>polymorphic_downcast</b> <p>The C++ built-in <b>static_cast</b> can be used for efficiently
template retains the efficiency of <b>static_cast</b> for non-debug downcasting pointers to polymorphic objects, but provides no error
compilations, but for debug compilations adds safety via an assert() that a <b>dynamic_cast</b> detection for the case where the pointer being cast actually points to
succeeds.</p> the wrong derived class. The <b>polymorphic_downcast</b> template retains
<p>The C++ built-in <b>dynamic_cast</b> can be used for downcasts and crosscasts the efficiency of <b>static_cast</b> for non-debug compilations, but for
of pointers to polymorphic objects, but error notification in the form of a debug compilations adds safety via an assert() that a <b>dynamic_cast</b>
returned value of 0 is inconvenient to test, or worse yet, easy to forget to succeeds.</p>
test. The <b>polymorphic_cast</b> template performs a <b>dynamic_cast</b>,
and throws an exception if the <b>dynamic_cast</b> returns 0.</p> <p>The C++ built-in <b>dynamic_cast</b> can be used for downcasts and
<p>A <b>polymorphic_downcast</b> is preferred when debug-mode tests will cover crosscasts of pointers to polymorphic objects, but error notification in
100% of the object types possibly cast and when non-debug-mode efficiency is an the form of a returned value of 0 is inconvenient to test, or worse yet,
issue. If these two conditions are not present, <b>polymorphic_cast</b> is easy to forget to test. The throwing form of <b>dynamic_cast</b>, which
preferred. It must also be used for crosscasts. It does an assert( works on references, can be used on pointers through the ugly expression
dynamic_cast&lt;Derived&gt;(x) == x ) where x is the base pointer, ensuring that &amp;<code>dynamic_cast&lt;T&amp;&gt;(*p)</code>, which causes undefined
not only is a non-zero pointer returned, but also that it correct in the behavior if <code>p</code> is <code>0</code>. The <b>polymorphic_cast</b>
presence of multiple inheritance.<b> Warning:</b>: Because <b>polymorphic_downcast</b> template performs a <b>dynamic_cast</b> on a pointer, and throws an
uses assert(), it violates the one definition rule (ODR) if NDEBUG is inconsistently exception if the <b>dynamic_cast</b> returns 0.</p>
defined across translation units. [See ISO Std 3.2]</p>
<p>The C++ built-in <b>dynamic_cast</b> must be used to cast references rather <p>A <b>polymorphic_downcast</b> is preferred when debug-mode tests will
than pointers. It is also the only cast that can be used to check whether cover 100% of the object types possibly cast and when non-debug-mode
a given interface is supported; in that case a return of 0 isn't an error efficiency is an issue. If these two conditions are not present,
condition.</p> <b>polymorphic_cast</b> is preferred. It must also be used for
<h3>polymorphic_cast and polymorphic_downcast synopsis</h3> crosscasts. It does an assert( dynamic_cast&lt;Derived&gt;(x) == x )
<blockquote> where x is the base pointer, ensuring that not only is a non-zero pointer
<pre>namespace boost { returned, but also that it correct in the presence of multiple
inheritance. <b>Warning:</b>: Because <b>polymorphic_downcast</b> uses
assert(), it violates the one definition rule (ODR) if NDEBUG is
inconsistently defined across translation units. [See ISO Std 3.2]</p>
<p>The C++ built-in <b>dynamic_cast</b> 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.</p>
<h3>polymorphic_cast and polymorphic_downcast synopsis</h3>
<blockquote>
<pre>
namespace boost {
template &lt;class Derived, class Base&gt; template &lt;class Derived, class Base&gt;
inline Derived polymorphic_cast(Base* x); inline Derived polymorphic_cast(Base* x);
@@ -70,11 +91,15 @@ inline Derived polymorphic_downcast(Base* x);
// Effects: assert( dynamic_cast&lt;Derived&gt;(x) == x ); // Effects: assert( dynamic_cast&lt;Derived&gt;(x) == x );
// Returns: static_cast&lt;Derived&gt;(x) // Returns: static_cast&lt;Derived&gt;(x)
}</pre> }
</blockquote> </pre>
<h3>polymorphic_downcast example</h3> </blockquote>
<blockquote>
<pre>#include &lt;boost/cast.hpp&gt; <h3>polymorphic_downcast example</h3>
<blockquote>
<pre>
#include &lt;boost/cast.hpp&gt;
... ...
class Fruit { public: virtual ~Fruit(){}; ... }; class Fruit { public: virtual ~Fruit(){}; ... };
class Banana : public Fruit { ... }; class Banana : public Fruit { ... };
@@ -82,26 +107,40 @@ class Banana : public Fruit { ... };
void f( Fruit * fruit ) { void f( Fruit * fruit ) {
// ... logic which leads us to believe it is a Banana // ... logic which leads us to believe it is a Banana
Banana * banana = boost::polymorphic_downcast&lt;Banana*&gt;(fruit); Banana * banana = boost::polymorphic_downcast&lt;Banana*&gt;(fruit);
...</pre> ...
</blockquote> </pre>
<h3><a name="numeric_cast">numeric_cast</a></h3> </blockquote>
<p>A <b>static_cast</b> or implicit conversion will not
detect failure to preserve range for numeric casts. The <b>numeric_cast</b> function <h3><a name="numeric_cast">numeric_cast</a></h3>
templates are similar to <b>static_cast</b> and certain (dubious)
implicit conversions in this respect, except that they detect loss of numeric <p>A <b>static_cast</b> or implicit conversion will not detect failure to
range. An exception is thrown when a runtime value-preservation check fails.</p> preserve range for numeric casts. The <b>numeric_cast</b> function
<p>The requirements on the argument and result types are:</p> templates are similar to <b>static_cast</b> and certain (dubious)
<blockquote> implicit conversions in this respect, except that they detect loss of
<ul> numeric range. An exception is thrown when a runtime value-preservation
<li>Both argument and result types are CopyConstructible [ISO Std 20.1.3].</li> check fails.</p>
<li>Both argument and result types are Numeric, defined by <code>std::numeric_limits&lt;&gt;::is_specialized</code>
being true.</li> <p>The requirements on the argument and result types are:</p>
<li>The argument can be converted to the result type using <b>static_cast</b>.</li>
</ul> <blockquote>
</blockquote> <ul>
<h3>numeric_cast synopsis</h3> <li>Both argument and result types are CopyConstructible [ISO Std
<blockquote> 20.1.3].</li>
<pre>namespace boost {
<li>Both argument and result types are Numeric, defined by
<code>std::numeric_limits&lt;&gt;::is_specialized</code> being
true.</li>
<li>The argument can be converted to the result type using
<b>static_cast</b>.</li>
</ul>
</blockquote>
<h3>numeric_cast synopsis</h3>
<blockquote>
<pre>
namespace boost {
class bad_numeric_cast : public std::bad_cast {...}; class bad_numeric_cast : public std::bad_cast {...};
@@ -112,11 +151,15 @@ template&lt;typename Target, typename Source&gt;
// overflow, as determined by std::numeric_limits // overflow, as determined by std::numeric_limits
// Returns: static_cast&lt;Target&gt;(arg) // Returns: static_cast&lt;Target&gt;(arg)
}</pre> }
</blockquote> </pre>
<h3>numeric_cast example</h3> </blockquote>
<blockquote>
<pre>#include &lt;boost/cast.hpp&gt; <h3>numeric_cast example</h3>
<blockquote>
<pre>
#include &lt;boost/cast.hpp&gt;
using namespace boost::cast; using namespace boost::cast;
void ariane(double vx) void ariane(double vx)
@@ -124,27 +167,36 @@ void ariane(double vx)
... ...
unsigned short dx = numeric_cast&lt;unsigned short&gt;(vx); unsigned short dx = numeric_cast&lt;unsigned short&gt;(vx);
... ...
}</pre> }
</blockquote> </pre>
<h3>numeric_cast rationale</h3> </blockquote>
<p>The form of the throws condition is specified so that != is not a required
operation.</p>
<h3>History</h3>
<p><b>polymorphic_cast</b> was suggested by Bjarne Stroustrup in &quot;The C++
Programming Language&quot;.<br>
<b>polymorphic_downcast</b> was contributed by <a href="../../people/dave_abrahams.htm">Dave
Abrahams</a>.<b><br>
numeric_cast</b> was contributed by <a href="../../people/kevlin_henney.htm">Kevlin
Henney</a>.</p>
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan
-->06 January, 2001<!--webbot bot="Timestamp" endspan i-checksum="38320"
--></p>
<p><EFBFBD> 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 &quot;as is&quot; without express or
implied warranty, and with no claim as to its suitability for any purpose.</p>
</body> <h3>numeric_cast rationale</h3>
<p>The form of the throws condition is specified so that != is not a
required operation.</p>
<h3>History</h3>
<p><b>polymorphic_cast</b> was suggested by Bjarne Stroustrup in "The C++
Programming Language".<br>
<b>polymorphic_downcast</b> was contributed by <a href=
"../../people/dave_abrahams.htm">Dave Abrahams</a>.<b><br>
numeric_cast</b> was contributed by <a href=
"../../people/kevlin_henney.htm">Kevlin Henney</a>.</p>
<hr>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan
-->06 January, 2001
<!--webbot bot="Timestamp" endspan i-checksum="38320"
--></p>
<p>&copy; 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.</p>
</body>
</html> </html>