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

📄 chap09.htm

📁 C++编程思想第二版第二卷
💻 HTM
📖 第 1 页 / 共 5 页
字号:
         << endl;
  }
  X* xp = 0;
  <font color=#0000ff>try</font> {
    <font color=#0000ff>typeid</font>(*xp); <font color=#009900>// Throws exception</font>
  } <font color=#0000ff>catch</font>(<font color=#0000ff>bad_typeid</font>) {
    cout &lt;&lt; <font color=#004488>"Bad typeid() expression"</font> &lt;&lt; endl;
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The failure, of course, is because
<B>b</B> doesn&#8217;t actually point to an <B>X</B> object. If an exception was
not thrown here, then <B>xr</B> would be unbound, and the guarantee that all
objects or references are constructed storage would be broken.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">An exception is also thrown if you try to
dereference a null pointer in the process of calling
<B>typeid(&#160;)<A NAME="Index562"></A><A NAME="Index563"></A></B>. The
Standard C++ exception is called
<B>bad_typeid<A NAME="Index564"></A><A NAME="Index565"></A><A NAME="Index566"></A></B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here (unlike the reference example above)
you can avoid the exception by checking for a nonzero pointer value before
attempting the operation; this is the preferred
practice.</FONT><A NAME="_Toc305593312"></A><A NAME="_Toc305628784"></A><A NAME="_Toc312374145"></A><A NAME="_Toc519042093"></A><BR></P></DIV>
<A NAME="Heading300"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Multiple
inheritance<BR><A NAME="Index567"></A><A NAME="Index568"></A><A NAME="Index569"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, the RTTI mechanisms must work
properly with all the complexities of multiple inheritance, including
<B>virtual</B> base classes:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:RTTIandMultipleInheritance.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include &lt;iostream&gt;
#include &lt;typeinfo&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>class</font> BB {
<font color=#0000ff>public</font>:
  <font color=#0000ff>virtual</font> <font color=#0000ff>void</font> f() {}
  <font color=#0000ff>virtual</font> ~BB() {}
};
<font color=#0000ff>class</font> B1 : <font color=#0000ff>virtual</font> <font color=#0000ff>public</font> BB {};
<font color=#0000ff>class</font> B2 : <font color=#0000ff>virtual</font> <font color=#0000ff>public</font> BB {};
<font color=#0000ff>class</font> MI : <font color=#0000ff>public</font> B1, <font color=#0000ff>public</font> B2 {};

<font color=#0000ff>int</font> main() {
  BB* bbp = <font color=#0000ff>new</font> MI; <font color=#009900>// Upcast</font>
  <font color=#009900>// Proper name detection:</font>
  cout &lt;&lt; <font color=#0000ff>typeid</font>(*bbp).name() &lt;&lt; endl;
  <font color=#009900>// Dynamic_cast works properly:</font>
  MI* mip = <font color=#0000ff>dynamic_cast</font>&lt;MI*&gt;(bbp);
  <font color=#009900>// Can't force old-style cast:</font>
  <font color=#009900>//! MI* mip2 = (MI*)bbp; // Compile error</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>typeid(&#160;) </B>properly detects
the name of the actual object, even through the <B>virtual</B> base class
pointer. The <B>dynamic_cast</B> also works correctly. But the compiler
won&#8217;t even allow you to try to force a cast the old way:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>MI* mip = (MI*)bbp; <font color=#009900>// Compile-time error</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It knows this is never the right thing to
do, so it requires that you use a
<B>dynamic_cast</B>.</FONT><A NAME="_Toc305593313"></A><A NAME="_Toc305628785"></A><A NAME="_Toc312374146"></A><A NAME="_Toc519042094"></A><BR></P></DIV>
<A NAME="Heading301"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Sensible uses for RTTI<BR><A NAME="Index570"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because it allows you to discover type
information from an anonymous polymorphic pointer, RTTI is ripe for misuse
<A NAME="Index571"></A>by the novice because RTTI may make sense before virtual
functions do. For many people coming from a procedural background, it&#8217;s
very difficult not to organize their programs into sets of <B>switch</B>
statements. They could accomplish this with RTTI and thus lose the very
important value of polymorphism <A NAME="Index572"></A>in code development and
maintenance. The intent of C++ is that you use virtual functions throughout your
code, and you only use RTTI when you must.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">However, using virtual functions as they
are intended requires that you have control of the base-class definition because
at some point in the extension of your program you may discover the base class
doesn&#8217;t include the virtual function you need. If the base class comes
from a library or is otherwise controlled by someone else, a solution to the
problem is RTTI: You can inherit a new type and add your extra member function.
Elsewhere in the code you can detect your particular type and call that member
function. This doesn&#8217;t destroy the polymorphism and extensibility of the
program, because adding a new type will not require you to hunt for switch
statements. However, when you add new code in your main body that requires your
new feature, you&#8217;ll have to detect your particular type.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Putting a feature in a base class might
mean that, for the benefit of one particular class, all the other classes
derived from that base require some meaningless stub of a virtual function. This
makes the interface less clear and annoys those who must redefine pure virtual
functions when they derive from that base class. For example, suppose that in
the <B>Wind5.cpp</B> program in Chapter XX you wanted to clear the spit valves
of all the instruments in your orchestra that had them. One option is to put a
<B>virtual ClearSpitValve(&#160;) </B>function in the base class
<B>Instrument</B>, but this is confusing because it implies that
<B>Percussion</B> and <B>electronic</B> instruments also have spit valves. RTTI
provides a much more reasonable solution in this case because you can place the
function in the specific class (<B>Wind </B>in this case) where it&#8217;s
appropriate.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Finally, RTTI will sometimes solve
efficiency <A NAME="Index573"></A><A NAME="Index574"></A>problems. If your code
uses polymorphism in a nice way, but it turns out that one of your objects
reacts to this general-purpose code in a horribly inefficient way, you can pick
that type out using RTTI and write case-specific code to improve the
efficiency.</FONT><A NAME="_Toc312374147"></A><A NAME="_Toc519042095"></A><BR></P></DIV>
<A NAME="Heading302"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Revisiting the trash recycler</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s the trash recycling
simulation from Chapter XX, rewritten to use RTTI instead of building the
information into the class hierarchy:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C09:Recycle2.cpp</font>
<font color=#009900>// Chapter XX example w/ RTTI</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"..</font><font color=#004488>/purge.h"</font>
#include &lt;fstream&gt;
#include &lt;vector&gt;
#include &lt;typeinfo&gt;
#include &lt;cstdlib&gt;
#include &lt;ctime&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
ofstream out(<font color=#004488>"recycle2.out"</font>);

<font color=#0000ff>class</font> Trash {
  <font color=#0000ff>float</font> _weight;
<font color=#0000ff>public</font>:
  Trash(<font color=#0000ff>float</font> wt) : _weight(wt) {}
  <font color=#0000ff>virtual</font> <font color=#0000ff>float</font> value() <font color=#0000ff>const</font> = 0;
  <font color=#0000ff>float</font> weight() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> _weight; }
  <font color=#0000ff>virtual</font> ~Trash() { out &lt;&lt; <font color=#004488>"~Trash()\n"</font>; }
};

<font color=#0000ff>class</font> Aluminum : <font color=#0000ff>public</font> Trash {
  <font color=#0000ff>static</font> <font color=#0000ff>float</font> val;
<font color=#0000ff>public</font>:
  Aluminum(<font color=#0000ff>float</font> wt) : Trash(wt) {}
  <font color=#0000ff>float</font> value() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> val; }
  <font color=#0000ff>static</font> <font color=#0000ff>void</font> value(<font color=#0000ff>int</font> newval) {
    val = newval;
  }
};

<font color=#0000ff>float</font> Aluminum::val = 1.67;

<font color=#0000ff>class</font> Paper : <font color=#0000ff>public</font> Trash {
  <font color=#0000ff>static</font> <font color=#0000ff>float</font> val;
<font color=#0000ff>public</font>:
  Paper(<font color=#0000ff>float</font> wt) : Trash(wt) {}
  <font color=#0000ff>float</font> value() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> val; }
  <font color=#0000ff>static</font> <font color=#0000ff>void</font> value(<font color=#0000ff>int</font> newval) {
    val = newval;
  }
};

<font color=#0000ff>float</font> Paper::val = 0.10;

<font color=#0000ff>class</font> Glass : <font color=#0000ff>public</font> Trash {
  <font color=#0000ff>static</font> <font color=#0000ff>float</font> val;
<font color=#0000ff>public</font>:
  Glass(<font color=#0000ff>float</font> wt) : Trash(wt) {}
  <font color=#0000ff>float</font> value() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> val; }
  <font color=#0000ff>static</font> <font color=#0000ff>void</font> value(<font color=#0000ff>int</font> newval) {
    val = newval;
  }
};

<font color=#0000ff>float</font> Glass::val = 0.23;

<font color=#009900>// Sums up the value of the Trash in a bin:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> Container&gt; <font color=#0000ff>void</font>
sumValue(Container&amp; bin, ostream&amp; os) {
  <font color=#0000ff>typename</font> Container::iterator tally = 
    bin.begin();
  <font color=#0000ff>float</font> val = 0;
  <font color=#0000ff>while</font>(tally != bin.end()) {
    val += (*tally)-&gt;weight() * (*tally)-&gt;value();
    os &lt;&lt; <font color=#004488>"weight of "</font>
        &lt;&lt; <font color=#0000ff>typeid</font>(*tally).name()
        &lt;&lt; <font color=#004488>" = "</font> &lt;&lt; (*tally)-&gt;weight() &lt;&lt; endl;
    tally++;
  }
  os &lt;&lt; <font color=#004488>"Total value = "</font> &lt;&lt; val &lt;&lt; endl;
}

<font color=#0000ff>int</font> main() {
  srand(time(0)); <font color=#009900>// Seed random number generator</font>
  vector&lt;Trash*&gt; bin;
  <font color=#009900>// Fill up the Trash bin:</font>
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 30; i++)
    <font color=#0000ff>switch</font>(rand() % 3) {
      <font color=#0000ff>case</font> 0 :
        bin.push_back(<font color=#0000ff>new</font> Aluminum(rand() % 100));
        <font color=#0000ff>break</font>;
      <font color=#0000ff>case</font> 1 :
        bin.push_back(<font color=#0000ff>new</font> Paper(rand() % 100));
        <font color=#0000ff>break</font>;
      <font color=#0000ff>case</font> 2 :
        bin.push_back(<font color=#0000ff>new</font> Glass(rand() % 100));
        <font color=#0000ff>break</font>;
    }
  <font color=#009900>// Note difference w/ chapter 14: Bins hold</font>
  <font color=#009900>// exact type of object, not base type:</font>
  vector&lt;Glass*&gt; glassBin;
  vector&lt;Paper*&gt; paperBin;
  vector&lt;Aluminum*&gt; alBin;
  vector&lt;Trash*&gt;::iterator sorter = bin.begin();
  <font color=#009900>// Sort the Trash:</font>
  <font color=#0000ff>while</font>(sorter != bin.end()) {
    Aluminum* ap =
      <font color=#0000ff>dynamic_cast</font>&lt;Aluminum*&gt;(*sorter);
    Paper* pp =
      <font color=#0000ff>dynamic_cast</font>&lt;Paper*&gt;(*sorter);
    Glass* gp =
      <font color=#0000ff>dynamic_cast</font>&lt;Glass*&gt;(*sorter);
    <font color=#0000ff>if</font>(ap) alBin.push_back(ap);
    <font color=#0000ff>if</font>(pp) paperBin.push_back(pp);
    <font color=#0000ff>if</font>(gp) glassBin.push_back(gp);
    sorter++;
  }
  sumValue(alBin, out);
  sumValue(paperBin, out);

⌨️ 快捷键说明

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