⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tut5-4.html

📁 a Complete C++ language tutorial on the cplusplus.com
💻 HTML
字号:
<HTML>
<HEAD>
<TITLE>C++ Tutorial: 5.4: Advanced Class Type-casting </TITLE>
<META NAME="description" CONTENT="Shows the use of new ANSI-C++ type-casting operators and typeid.">
<META NAME="keywords" CONTENT="reinterpret_cast, static_cast, dynamic_cast, const_cast, typeid, typeinfo, type_info">
</HEAD>

<BODY BGCOLOR="white">

<!--captut-->
<CENTER>
<TABLE WIDTH=100% CELLPADDING=0 CELLSPACING=1 BORDER=0>
<TR><TD WIDTH=90%>
 <FONT SIZE=4> Section 5.4 </FONT><BR>
 <FONT SIZE=5><B>Advanced Class Type-casting</B></FONT>
</TD><TD><!--ad--><!--#include virtual="/ad/ad468.shtml"--><!--/ad-->
</TD><TD VALIGN="bottom"><A HREF="http://www.cplusplus.com/doc/tutorial/">
 <IMG SRC="head.gif" ALT="cplusplus.com" BORDER=0></A></TD></TR>
<TR><TD BGCOLOR="#0000FF" ALIGN="center" COLSPAN=3>
 <IMG SRC="head0.gif" WIDTH=2 HEIGHT=2 BORDER=0></TD></TR>
</TABLE>
</CENTER>
<!--/captut-->

<P>
Until now, in order to type-cast a simple object to another we have used
the traditional type casting operator. For example, to cast a floating point number
of type <TT><B>double</B></TT> to an integer of type <TT><B>int</B></TT>
we have used:
<BLOCKQUOTE><TT>
int i;<BR>
double d;<BR>
i = (int) d;
</TT></BLOCKQUOTE>
or also
<BLOCKQUOTE><TT>
i = int (d);
</TT></BLOCKQUOTE>
This is quite good for basic types that have standard defined conversions,
however this operators can also be indiscriminately applied on classes
and pointers to classes. So, it is perfectly valid to write things like:

<P>
<CENTER>
<TABLE WIDTH=100% CELLPADDING=5 CELLSPACING=5><TR><TD BGCOLOR="#FFFFBF" WIDTH=50% VALIGN="top">
<TT><PRE><I>// class type-casting</I>
#include &lt;iostream.h&gt;

class CDummy {
    int i;
};

class CAddition {
	int x,y;
  public:
	CAddition (int a, int b) { x=a; y=b; }
	int result() { return x+y;}
};

int main () {
  CDummy d;
  CAddition * padd;
  padd = (CAddition*) &amp;d;
  cout &lt;&lt; padd-&gt;result();
  return 0;
}
</PRE></TT>
</TD><TD BGCOLOR="silver" WIDTH=50% VALIGN="top"><TT>
&nbsp;
</TT></TD></TR></TABLE>
</CENTER>

<P>
Although the previous program in sintactically correct in C++
(in fact it will compile with no warnings on most compilers)
it is code with not much sense since we use
function <TT><B>result</B></TT>, that is a member of <TT><B>CAddition</B></TT>,
without having declared an object of that class:
 <TT><B>padd</B></TT> is not an object, it is only
a pointer which we have assigned the address of a non related object.
When accessing its <TT><B>result</B></TT>
member it will produce a run-time error or, at best, just an unexpected result.
<P>
In order to control these types of conversions between classes,
ANSI-C++ standard has defined four new casting operators:
<TT><B>reinterpret_cast</B></TT>, <TT><B>static_cast</B></TT>, <TT><B>dynamic_cast</B></TT>
and <TT><B>const_cast</B></TT>.
All of them have the same format when used:
<BLOCKQUOTE><TT><PRE>
<B>reinterpret_cast &lt;</B><I>new_type</I><B>&gt; (</B><I>expression</I><B>)</B>
<B>    dynamic_cast &lt;</B><I>new_type</I><B>&gt; (</B><I>expression</I><B>)</B>
<B>     static_cast &lt;</B><I>new_type</I><B>&gt; (</B><I>expression</I><B>)</B>
<B>      const_cast &lt;</B><I>new_type</I><B>&gt; (</B><I>expression</I><B>)</B>
</PRE></TT></BLOCKQUOTE>

Where <TT><I>new_type</I></TT> is the destination type to which
<TT><I>expression</I></TT> has to be casted. To make an easily understandable
parallelism with traditional type-casting operators these expression mean:
<BLOCKQUOTE><TT>
<B>(</B><I>new_type</I><B>)</B> <I>expression</I><BR>
<I>new_type</I> <B>(</B><I>expression</I><B>)</B><BR>
</TT></BLOCKQUOTE>
but with their own special characteristics.
<P>
<H2>reinterpret_cast</H2>
<TT><B>reinterpret_cast</B></TT> casts a pointer to any other type of pointer.
It also allows casting from a pointer to an integer type and vice versa.
<P>
This operator can cast pointers between non-related classed.
The operation results is a simple binary copy of the value from one pointer to the other.
The content pointed does not pass any kind of check nor transformation between types.
<P>
In the case that the copy is performed from a pointer to an integer, the
interpretation of its content is system dependent and therefore any implementation is
non portable.
A pointer casted to an integer large enough to fully contain it can be
casted back to a valid pointer.
<BLOCKQUOTE><TT>
class A {};<BR>
class B {};<BR>
A * a = new A;<BR>
B * b = reinterpret_cast&lt;B*&gt;(a);<BR>
</TT></BLOCKQUOTE>
<TT><B>reinterpret_cast</B></TT> treats all pointers exactly as traditional
type-casting operators do.
<P>
<H2>static_cast</H2>
<TT><B>static_cast</B></TT> performs any casting that can be implicitly performed 
as well as the inverse cast (even if this is not allowed implicitly).
<P>
Applied to pointers to classes, that is to say that it allows to cast a pointer of a derived
class to its base class (this is a valid conversion that can be implicitly performed)
and it can also perform the inverse: cast a base class to its derivated class.
<P>
In this last case the base class that is being casted is not checked to
determine wether this is a complete class of the destination type or not.
<BLOCKQUOTE><TT>
class Base {};<BR>
class Derived: public Base {};<BR>
Base * a = new Base;<BR>
Derived * b = static_cast&lt;Derived*&gt;(a);<BR>
</TT></BLOCKQUOTE>
<TT><B>static_cast</B></TT>, aside from manipulating pointers to classes,
can also be used to perform conversions explicitly defined in classes,
as well as to perform standard conversions between fundamental types:
<BLOCKQUOTE><TT>
double d=3.14159265;<BR>
int i = static_cast&lt;int&gt;(d);
</TT></BLOCKQUOTE
<P>
<H2>dynamic_cast</H2>
<TT><B>dynamic_cast</B></TT> is exclusively used with pointers and references to objects.
It allows any type-casting that can be implicitly performed as well as
the inverse one when used with polymorphic classes, however, unlike
<TT><B>static_cast</B></TT>, <TT><B>dynamic_cast</B></TT> checks, in this last case,
if the operation is valid. That is to say, it checks if the casting
is going to return a valid complete object of the requested type.
<P>
Checking is performed during run-time execution. If the pointer being casted
is not a pointer to a valid complete object of the requested type, the value
returned is a <TT><B>NULL</B></TT> pointer.

<BLOCKQUOTE><TT>
class Base { virtual dummy(){}; };<BR>
class Derived : public Base { };<BR>&nbsp;<BR>
Base* b1 = new Derived;<BR>
Base* b2 = new Base;<BR>
Derived* d1 = dynamic_cast&lt;Derived*&gt;(b1); &nbsp; <I>// succeeds</I><BR>
Derived* d2 = dynamic_cast&lt;Derived*&gt;(b2); &nbsp; <I>// fails: returns NULL</I><BR>
</TT></BLOCKQUOTE>
<P>

If the type-casting is performed to a reference type and this casting is not possible
an <I>exception</I> of type <TT><B>bad_cast</B></TT> is thrown:
<BLOCKQUOTE><TT>
class Base { virtual dummy(){}; };<BR>
class Derived : public Base { };<BR>&nbsp;<BR>
Base* b1 = new Derived;<BR>
Base* b2 = new Base;<BR>
Derived d1 = dynamic_cast&lt;Derived&*&gt;(b1); &nbsp; <I>// succeeds</I><BR>
Derived d2 = dynamic_cast&lt;Derived&*&gt;(b2); &nbsp; <I>// fails: exception thrown</I><BR>
</TT></BLOCKQUOTE>

<P>
<H2>const_cast</H2>
This type of casting manipulates the <I>const</I> attribute of the passed object,
either to be set or removed:

<BLOCKQUOTE><TT>
class C {};<BR>
const C * a = new C;<BR>
C * b = const_cast&lt;C*&gt; (a);<BR>
</TT></BLOCKQUOTE>
Neither of the other three new <TT><B>cast</B></TT> operators can modify the
constness of an object.

<P>
<H2>typeid</H2>
ANSI-C++ also defines a new operator called <TT><B>typeid</B></TT> that allows
checking the type of an expression:
<BLOCKQUOTE><TT><B>typeid (</B><I>expression</I><B>)</B></TT></BLOCKQUOTE>
this operator returns a refernece to a constant object of type <TT><B>type_info</B></TT>
that is defined in the standard header file <TT><B>&lt;typeinfo&gt;</B></TT>.
This returned value can be compared with another using operators <TT>==</TT>
and <TT>!=</TT> or can serve to obtain a string of characters
representing the data type or class name by using its <TT><B>name()</B></TT> method.

<P>
<CENTER>
<TABLE WIDTH=100% CELLPADDING=5 CELLSPACING=5><TR><TD BGCOLOR="#FFFFBF" WIDTH=50% VALIGN="top">
<TT><PRE><I>// typeid, typeinfo</I>
#include &lt;iostream.h&gt;
#include &lt;typeinfo&gt;

class CDummy { };

int main () {
  CDummy* a,b;
  if (typeid(a) != typeid(b))
  {
    cout &lt;&lt; "a and b are of different types:\n";
    cout &lt;&lt; "a is: " &lt;&lt; typeid(a).name() &lt;&lt; '\n';
    cout &lt;&lt; "b is: " &lt;&lt; typeid(b).name() &lt;&lt; '\n';
  }
  return 0;
}
</PRE></TT>
</TD><TD BGCOLOR="silver" WIDTH=50% VALIGN="top"><TT><B>
a and b are of different types:<BR>
a is: class CDummy *<BR>
b is: class CDummy
</B></TT></TD></TR></TABLE>
</CENTER>

<!--cuatut-->
<P>
<CENTER><TABLE WIDTH=100% CELLPADDING=0 CELLSPACING=0 BORDER=0>
 <TR><TD BGCOLOR="#0000FF"><IMG SRC="head0.gif" WIDTH=2 HEIGHT=2></TD></TR>
 <TR><TD ALIGN="right"><FONT FACE="arial,helvetica" SIZE=1>&copy; The C++ Resources Network, 2000-2003 - All rights reserved</FONT></TD></TR>
</TABLE></CENTER>
<P>
<CENTER>
<TABLE CELLPADDING=0 WIDTH=100%>
<TR><TD ALIGN="right" WIDTH=45%><A HREF="tut5-3.html">
 <IMG SRC="butnback.gif" ALIGN="right" BORDER=0>
 Previous:<BR><B>5-3. Exception handling.</B></A></TD>
<TD ALIGN="center" WIDTH=10%><A HREF="index.html">
 <IMG SRC="butnindx.gif" BORDER=0><BR>
 index</A></TD>
<TD ALIGN="left" WIDTH=45%><A HREF="tut5-5.html">
 <IMG SRC="butnnext.gif" ALIGN="left" BORDER=0>
 Next:<BR><B>5-5. Preprocessor directives.</B></A>
</TD></TR></TABLE>
</CENTER>
<!--/cuatut-->

</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -