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

📄 ei41.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<UL><PRE>  return data;
}
</PRE>
</UL><A NAME="7660"></A>
<UL><PRE>
Stack::~Stack()                   // delete all in stack
{
  while (top) {
    StackNode *toDie = top;       // get ptr to top node
    top = top-&gt;next;              // move to next node
    delete toDie;                 // delete former top node
  }
}
</PRE>
</UL><A NAME="21290"></A>
<UL><PRE>bool Stack::empty() const
{ return top == 0; }
</PRE>
</UL><A NAME="7669"></A>
<P><A NAME="dingp11"></A>
There's nothing riveting about these implementations. In fact, the only interesting thing about them is this: you are able to write each member function knowing essentially <I>nothing</I> about <CODE>T</CODE>. (You assume you can call <CODE>T</CODE>'s copy constructor, but, as <A HREF="./EI45_FR.HTM#8160" TARGET="_top">Item 45</A> explains, that's a pretty reasonable assumption.) The code you write for construction, destruction, pushing, popping, and determining whether the stack is empty is the same, no matter what <CODE>T</CODE> is. Except for the assumption that you can call <CODE>T</CODE>'s copy constructor, the behavior of a <CODE>stack</CODE> does not depend on <CODE>T</CODE> in any way. That's the hallmark of a template class: the behavior doesn't depend on the <NOBR>type.<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="7672"></A>
<P><A NAME="dingp12"></A>
Turning your <CODE>Stack</CODE> class into a template, by the way, is so simple, even <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>&deg;</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=dilbert" onMouseOver = "self.status = 'Dilbert'; return true" onMouseOut = "self.status = self.defaultStatus" TARGET="_top">Dilbert</NOBR></A>'s pointy-haired boss could do <NOBR>it:<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<A NAME="7674"></A>
<UL><PRE>template&lt;class T&gt; class Stack {
</PRE>
</UL><A NAME="7675"></A>
<UL><PRE>
  ...                          // <I>exactly</I> the same as above
</PRE>
</UL><A NAME="7676"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7686"></A>
<P><A NAME="dingp13"></A>
<A NAME="p188"></A>But on to cats. Why won't templates work with <NOBR>cats?<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P>
<A NAME="7687"></A>
<P><A NAME="dingp14"></A>
Reread the specification and note the requirement that "each breed of cat eats and sleeps in its own endearing way." That means you're going to have to implement <I>different behavior</I> for each type of cat. You can't just write a single function to handle all cats, all you can do is <I>specify an interface</I> for a function that each type of cat must implement. Aha! The way to propagate a function <I>interface only</I> is to declare a pure virtual function (see <A HREF="./EI36_FR.HTM#7007" TARGET="_top">Item 36</A>):<SCRIPT>create_link(14);</SCRIPT>
</P>
<A NAME="7692"></A>
<UL><PRE>class Cat {
public:
  virtual ~Cat();                     // see <A HREF="./EI14_FR.HTM#223029" TARGET="_top">Item 14</A>
</PRE>
</UL><A NAME="7696"></A>
<UL><PRE>
  virtual void eat() = 0;             // all cats eat
  virtual void sleep() = 0;           // all cats sleep
};
</PRE>
</UL><A NAME="7697"></A>
<P><A NAME="dingp15"></A>
Subclasses of <CODE>Cat</CODE> &#151; say, <CODE>Siamese</CODE> and <CODE>BritishShortHairedTabby</CODE> &#151; must of course redefine the <CODE>eat</CODE> and <CODE>sleep</CODE> function interfaces they <NOBR>inherit:<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>
<A NAME="7699"></A>
<UL><PRE>class Siamese: public Cat {
public:
  void eat();
  void sleep();
</PRE>
</UL><A NAME="7700"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="7701"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7703"></A>
<UL><PRE>class BritishShortHairedTabby: public Cat {
public:
  void eat();
  void sleep();
</PRE>
</UL><A NAME="7704"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="7705"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7706"></A>
<P><A NAME="dingp16"></A>
Okay, you now know why templates work for the <CODE>Stack</CODE> class and why they won't work for the <CODE>Cat</CODE> class. You also know why inheritance works for the <CODE>Cat</CODE> class. The only remaining question is why inheritance won't work for the <CODE>Stack</CODE> class. To see why, try to declare the root class of a <CODE>Stack</CODE> hierarchy, the single class from which all other stack classes would <NOBR>inherit:<SCRIPT>create_link(16);</SCRIPT>
</NOBR></P>
<A NAME="7708"></A>
<UL><PRE>class Stack {      // a stack of anything
public:
  virtual void push(const ??? object) = 0;
  virtual ??? pop() = 0;
</PRE>
</UL><A NAME="7709"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="7710"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7711"></A>
<P><A NAME="dingp17"></A>
<A NAME="p189"></A>Now the difficulty becomes clear. What types are you going to declare for the pure virtual functions <CODE>push</CODE> and <CODE>pop</CODE>? Remember that each subclass must redeclare the virtual functions it inherits with <I>exactly</I> the same parameter types and with return types consistent with the base class declarations. Unfortunately, a stack of <CODE>int</CODE>s will want to push and pop <CODE>int</CODE> objects, whereas a stack of, say, <CODE>Cat</CODE>s, will want to push and pop <CODE>Cat</CODE> objects. How can the <CODE>Stack</CODE> class declare its pure virtual functions in such a way that clients can create both stacks of <CODE>int</CODE>s and stacks of <CODE>Cat</CODE>s? The cold, hard truth is that it can't, and that's why inheritance is unsuitable for creating <NOBR>stacks.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<A NAME="7714"></A>
<P><A NAME="dingp18"></A>
But maybe you're the sneaky type. Maybe you think you can outsmart your compilers by using generic (<CODE>void*</CODE>) pointers. As it turns out, generic pointers don't help you here. You simply can't get around the requirement that a virtual function's declarations in derived classes must never contradict its declaration in the base class. However, generic pointers can help with a different problem, one related to the efficiency of classes generated from templates. For details, see <A HREF="./EI42_FR.HTM#21052" TARGET="_top">Item 42</A>.<SCRIPT>create_link(18);</SCRIPT>
</P>
<A NAME="21398"></A>
<P><A NAME="dingp19"></A>
Now that we've dispensed with stacks and cats, we can summarize the lessons of this Item as <NOBR>follows:<SCRIPT>create_link(19);</SCRIPT>
</NOBR></P><UL><A NAME="7773"></A>
<A NAME="dingp20"></A><LI>A template should be used to generate a collection of classes when the type of the objects <I>does not</I> affect the behavior of the class's functions.<SCRIPT>create_link(20);</SCRIPT>

<A NAME="7774"></A>
<A NAME="dingp21"></A><LI>Inheritance should be used for a collection of classes when the type of the objects <I>does</I> affect the behavior of the class's functions.<SCRIPT>create_link(21);</SCRIPT>

</UL></P>
<A NAME="21477"></A>
<P><A NAME="dingp22"></A>
Internalize these two little bullet points, and you'll be well on your way to mastering the choice between inheritance and <NOBR>templates.<SCRIPT>create_link(22);</SCRIPT>
</NOBR></P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI40_FR.HTM" TARGET="_top">Item 40: Differentiate between inheritance and templates.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI42_FR.HTM" TARGET="_top">Item 42: Use private inheritance judiciously.</A></FONT></DIV>

</BODY>
</HTML>

⌨️ 快捷键说明

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