mirror of
https://github.com/SphereServer/Source-X
synced 2026-08-13 10:23:05 -04:00
219 lines
No EOL
7.9 KiB
HTML
219 lines
No EOL
7.9 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<TITLE>C++ Tutorial: 5.4: Advanced Class Type-casting </TITLE>
|
|
</HEAD>
|
|
|
|
<BODY BGCOLOR="white">
|
|
|
|
<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 <iostream.h>
|
|
|
|
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*) &d;
|
|
cout << padd->result();
|
|
return 0;
|
|
}
|
|
</PRE></TT>
|
|
</TD><TD BGCOLOR="silver" WIDTH=50% VALIGN="top"><TT>
|
|
|
|
</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 <</B><I>new_type</I><B>> (</B><I>expression</I><B>)</B>
|
|
<B> dynamic_cast <</B><I>new_type</I><B>> (</B><I>expression</I><B>)</B>
|
|
<B> static_cast <</B><I>new_type</I><B>> (</B><I>expression</I><B>)</B>
|
|
<B> const_cast <</B><I>new_type</I><B>> (</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<B*>(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<Derived*>(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<int>(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> <BR>
|
|
Base* b1 = new Derived;<BR>
|
|
Base* b2 = new Base;<BR>
|
|
Derived* d1 = dynamic_cast<Derived*>(b1); <I>// succeeds</I><BR>
|
|
Derived* d2 = dynamic_cast<Derived*>(b2); <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> <BR>
|
|
Base* b1 = new Derived;<BR>
|
|
Base* b2 = new Base;<BR>
|
|
Derived d1 = dynamic_cast<Derived&*>(b1); <I>// succeeds</I><BR>
|
|
Derived d2 = dynamic_cast<Derived&*>(b2); <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<C*> (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><typeinfo></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 <iostream.h>
|
|
#include <typeinfo>
|
|
|
|
class CDummy { };
|
|
|
|
int main () {
|
|
CDummy* a,b;
|
|
if (typeid(a) != typeid(b))
|
|
{
|
|
cout << "a and b are of different types:\n";
|
|
cout << "a is: " << typeid(a).name() << '\n';
|
|
cout << "b is: " << typeid(b).name() << '\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>
|
|
|
|
</BODY>
|
|
</HTML> |