📄 chap09.htm
字号:
For example,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:DynamicCast.cpp</font>
<font color=#009900>// Using the standard dynamic_cast operation</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <cassert>
#include <typeinfo>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> D1 {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> func() {}
<font color=#0000ff>virtual</font> ~D1() {}
};
<font color=#0000ff>class</font> D2 {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> bar() {}
};
<font color=#0000ff>class</font> MI : <font color=#0000ff>public</font> D1, <font color=#0000ff>public</font> D2 {};
<font color=#0000ff>class</font> Mi2 : <font color=#0000ff>public</font> MI {};
<font color=#0000ff>int</font> main() {
D2* d2 = <font color=#0000ff>new</font> Mi2;
Mi2* mi2 = <font color=#0000ff>dynamic_cast</font><Mi2*>(d2);
MI* mi = <font color=#0000ff>dynamic_cast</font><MI*>(d2);
D1* d1 = <font color=#0000ff>dynamic_cast</font><D1*>(d2);
assert(<font color=#0000ff>typeid</font>(d2) != <font color=#0000ff>typeid</font>(Mi2*));
assert(<font color=#0000ff>typeid</font>(d2) == <font color=#0000ff>typeid</font>(D2*));
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This has the extra complication of
multiple
inheritance<A NAME="Index540"></A><A NAME="Index541"></A><A NAME="Index542"></A>.
If you create an <B>mi2</B> and upcast it to the root (in this case, one of the
two possible roots is chosen), then the <B>dynamic_cast</B> back to either of
the derived levels <B>MI</B> or <B>mi2</B> is successful. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can even cast from one root to the
other:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE> D1* d1 = <font color=#0000ff>dynamic_cast</font><D1*>(d2);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This is successful because <B>D2</B> is
actually pointing to an <B>mi2</B> object, which contains a subobject of type
<B>d1</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Casting to intermediate levels brings up
an interesting difference between <B>dynamic_cast</B> and
<B>typeid( )<A NAME="Index543"></A><A NAME="Index544"></A><A NAME="Index545"></A></B>.
<B>typeid( )</B> always produces a reference to a <B>typeinfo</B> object
that describes the <I>exact</I> type of the object. Thus it doesn’t give
you intermediate-level information. In the following expression (which is true),
<B>typeid( )</B> doesn’t see <B>d2</B> as a pointer to the derived
type, like <B>dynamic_cast</B> does:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>typeid</font>(d2) != <font color=#0000ff>typeid</font>(Mi2*)</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The type of <B>D2</B> is simply the exact
type of the pointer:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>typeid</font>(d2) == <font color=#0000ff>typeid</font>(D2*)</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><A NAME="_Toc312374141"></A><A NAME="_Toc519042089"></A><BR></P></DIV>
<A NAME="Heading296"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
void pointers</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Run-time type identification
doesn’t work with <B>void</B>
pointers<A NAME="Index546"></A><A NAME="Index547"></A>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:Voidrtti.cpp</font>
<font color=#009900>// RTTI & void pointers</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <iostream>
#include <typeinfo>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Stimpy {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> happy() {}
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> joy() {}
<font color=#0000ff>virtual</font> ~Stimpy() {}
};
<font color=#0000ff>int</font> main() {
<font color=#0000ff>void</font>* v = <font color=#0000ff>new</font> Stimpy;
<font color=#009900>// Error:</font>
<font color=#009900>//! Stimpy* s = dynamic_cast<Stimpy*>(v);</font>
<font color=#009900>// Error:</font>
<font color=#009900>//! cout << typeid(*v).name() << endl;</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A <B>void*</B> truly means “no type
information at
all.”</FONT><A NAME="_Toc312374142"></A><A NAME="_Toc519042090"></A><BR></P></DIV>
<A NAME="Heading297"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Using RTTI with templates<BR><A NAME="Index548"></A><A NAME="Index549"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Templates generate many different class
names, and sometimes you’d like to print out information about what class
you’re in. RTTI provides a convenient way to do this. The following
example revisits the code in Chapter XX to print out the order of constructor
and destructor
calls<A NAME="Index550"></A><A NAME="Index551"></A><A NAME="Index552"></A>
without using a preprocessor macro:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:ConstructorOrder.cpp</font>
<font color=#009900>// Order of constructor calls</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <iostream>
#include <typeinfo>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>template</font><<font color=#0000ff>int</font> id> <font color=#0000ff>class</font> Announce {
<font color=#0000ff>public</font>:
Announce() {
cout << <font color=#0000ff>typeid</font>(*<font color=#0000ff>this</font>).name()
<< <font color=#004488>" constructor "</font> << endl;
}
~Announce() {
cout << <font color=#0000ff>typeid</font>(*<font color=#0000ff>this</font>).name()
<< <font color=#004488>" destructor "</font> << endl;
}
};
<font color=#0000ff>class</font> X : <font color=#0000ff>public</font> Announce<0> {
Announce<1> m1;
Announce<2> m2;
<font color=#0000ff>public</font>:
X() { cout << <font color=#004488>"X::X()"</font> << endl; }
~X() { cout << <font color=#004488>"X::~X()"</font> << endl; }
};
<font color=#0000ff>int</font> main() { X x; } <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The
<B><typeinfo><A NAME="Index553"></A></B> header must be included to call
any member functions for the <B>typeinfo</B> object returned by
<B>typeid( )</B>. The template uses a constant <B>int</B> to differentiate
one class from another, but class arguments will work as well. Inside both the
constructor and destructor, RTTI information is used to produce the name of the
class to print. The class <B>X</B> uses both inheritance and composition to
create a class that has an interesting order of constructor and destructor
calls.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This technique is often useful in
situations when you’re trying to understand how the language
works.</FONT><A NAME="_Toc305593311"></A><A NAME="_Toc305628783"></A><A NAME="_Toc312374143"></A><A NAME="_Toc519042091"></A><BR></P></DIV>
<A NAME="Heading298"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
References<BR><A NAME="Index554"></A><A NAME="Index555"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">RTTI must adjust somewhat to work with
references. The contrast between pointers and references occurs because a
reference is always dereferenced for you by the compiler, whereas a
pointer’s type <I>or</I> the type it points to may be examined.
Here’s an example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:RTTIwithReferences.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <cassert>
#include <typeinfo>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> B {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>float</font> f() { <font color=#0000ff>return</font> 1.0;}
<font color=#0000ff>virtual</font> ~B() {}
};
<font color=#0000ff>class</font> D : <font color=#0000ff>public</font> B { <font color=#009900>/* ... */</font> };
<font color=#0000ff>int</font> main() {
B* p = <font color=#0000ff>new</font> D;
B& r = *p;
assert(<font color=#0000ff>typeid</font>(p) == <font color=#0000ff>typeid</font>(B*));
assert(<font color=#0000ff>typeid</font>(p) != <font color=#0000ff>typeid</font>(D*));
assert(<font color=#0000ff>typeid</font>(r) == <font color=#0000ff>typeid</font>(D));
assert(<font color=#0000ff>typeid</font>(*p) == <font color=#0000ff>typeid</font>(D));
assert(<font color=#0000ff>typeid</font>(*p) != <font color=#0000ff>typeid</font>(B));
assert(<font color=#0000ff>typeid</font>(&r) == <font color=#0000ff>typeid</font>(B*));
assert(<font color=#0000ff>typeid</font>(&r) != <font color=#0000ff>typeid</font>(D*));
assert(<font color=#0000ff>typeid</font>(r.f()) == <font color=#0000ff>typeid</font>(<font color=#0000ff>float</font>));
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Whereas the type of pointer that
<B>typeid( )</B> sees is the base type and not the derived type, the type
it sees for the reference is the derived type:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>typeid</font>(p) == <font color=#0000ff>typeid</font>(B*)
<font color=#0000ff>typeid</font>(p) != <font color=#0000ff>typeid</font>(D*)
<font color=#0000ff>typeid</font>(r) == <font color=#0000ff>typeid</font>(D)</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Conversely, what the pointer points to is
the derived type and not the base type, and taking the address of the reference
produces the base type and not the derived type:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>typeid</font>(*p) == <font color=#0000ff>typeid</font>(D)
<font color=#0000ff>typeid</font>(*p) != <font color=#0000ff>typeid</font>(B)
<font color=#0000ff>typeid</font>(&r) == <font color=#0000ff>typeid</font>(B*)
<font color=#0000ff>typeid</font>(&r) != <font color=#0000ff>typeid</font>(D*)</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Expressions may also be used with the
<B>typeid( )</B> operator because they have a type as
well:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>typeid</font>(r.f()) == <font color=#0000ff>typeid</font>(<font color=#0000ff>float</font>)</PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><A NAME="_Toc312374144"></A><A NAME="_Toc519042092"></A><BR></P></DIV>
<A NAME="Heading299"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Exceptions</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you perform a
<B>dynamic_cast<A NAME="Index556"></A><A NAME="Index557"></A></B> to a
reference, the result must be assigned to a reference. But what happens if the
cast fails? There are no null
references<A NAME="Index558"></A><A NAME="Index559"></A>, so this is the perfect
place to throw an exception; the Standard C++ exception type is
<B>bad_cast</B>,<A NAME="Index560"></A><A NAME="Index561"></A> but in the
following example the ellipses are used to catch any exception:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:RTTIwithExceptions.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <typeinfo>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> X { <font color=#0000ff>public</font>: <font color=#0000ff>virtual</font> ~X(){} };
<font color=#0000ff>class</font> B { <font color=#0000ff>public</font>: <font color=#0000ff>virtual</font> ~B(){} };
<font color=#0000ff>class</font> D : <font color=#0000ff>public</font> B {};
<font color=#0000ff>int</font> main() {
D d;
B & b = d; <font color=#009900>// Upcast to reference</font>
<font color=#0000ff>try</font> {
X& xr = <font color=#0000ff>dynamic_cast</font><X&>(b);
} <font color=#0000ff>catch</font>(...) {
cout << <font color=#004488>"dynamic_cast<X&>(b) failed"</font>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -