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

📄 ei43.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<A NAME="8046"></A>
<UL><PRE>class Cricket: public CartoonCharacter {
public:
  virtual void dance();
  virtual void sing();
};
</PRE>
</UL><A NAME="8047"></A>
<P><A NAME="dingp45"></A>
As you sit down to implement the <CODE>Cricket</CODE> class, you realize that a lot of the code you wrote for the <CODE>Grasshopper</CODE> class can be reused. However, it needs to be tweaked a bit here and there to account for the differences in singing and dancing between grasshoppers and crickets. You are suddenly struck by a clever way to reuse your existing code: you'll implement the <CODE>Cricket</CODE> class <I>in terms of</I> the <CODE>Grasshopper</CODE> class, and you'll use virtual functions to allow the <CODE>Cricket</CODE> class to customize <CODE>Grasshopper</CODE> <NOBR>behavior!<SCRIPT>create_link(45);</SCRIPT>
</NOBR></P>
<A NAME="8050"></A>
<P><A NAME="dingp46"></A>
You immediately recognize that these twin requirements &#151; an is-implemented-in-terms-of relationship and the ability to redefine virtual functions &#151; mean that <CODE>Cricket</CODE> will have to privately inherit from <CODE>Grasshopper</CODE>, but of course a cricket is still a cartoon character, so you redefine <CODE>Cricket</CODE> to inherit from both <CODE>Grasshopper</CODE> and <CODE>CartoonCharacter</CODE>:<SCRIPT>create_link(46);</SCRIPT>
</P>
<A NAME="8055"></A>
<UL><PRE>class Cricket: public CartoonCharacter,
               private Grasshopper {
public:
  virtual void dance();
  virtual void sing();
};
</PRE>
</UL><A NAME="8056"></A>
<P><A NAME="dingp47"></A>
You then set out to make the necessary modifications to the <CODE>Grasshopper</CODE> class. In particular, you need to declare some new virtual functions for <CODE>Cricket</CODE> to <NOBR>redefine:<SCRIPT>create_link(47);</SCRIPT>
</NOBR></P>
<A NAME="8058"></A>
<UL><PRE><A NAME="p207"></A>class Grasshopper: public CartoonCharacter {
public:
  virtual void dance();
  virtual void sing();
</PRE>
</UL><A NAME="8059"></A>
<UL><PRE>protected:
  virtual void danceCustomization1();
  virtual void danceCustomization2();
</PRE>
</UL><A NAME="8060"></A>
<UL><PRE>  virtual void singCustomization();
};
</PRE>
</UL><A NAME="8061"></A>
<A NAME="dingp48"></A>Dancing for grasshoppers is now defined like this:<SCRIPT>create_link(48);</SCRIPT>

<A NAME="8063"></A>
<UL><PRE>void Grasshopper::dance()
{
  <I>perform common dancing actions;</I>
</PRE>
</UL><A NAME="8064"></A>
<UL><PRE>  danceCustomization1();
</PRE>
</UL><A NAME="8065"></A>
<UL><PRE>  <I>perform more common dancing actions;</I>
</PRE>
</UL><A NAME="8066"></A>
<UL><PRE>  danceCustomization2();
</PRE>
</UL><A NAME="8067"></A>
<UL><PRE>  <I>perform final common dancing actions;</I>
}
</PRE>
</UL><A NAME="8068"></A>
<P><A NAME="dingp49"></A>
Grasshopper singing is similarly <NOBR>orchestrated.<SCRIPT>create_link(49);</SCRIPT>
</NOBR></P>
<A NAME="8069"></A>
<P><A NAME="dingp50"></A>
Clearly, the <CODE>Cricket</CODE> class must be updated to take into account the new virtual functions it must <NOBR>redefine:<SCRIPT>create_link(50);</SCRIPT>
</NOBR></P>
<A NAME="70108"></A>
<UL><PRE>class Cricket:public CartoonCharacter,
      private Grasshopper {
public:
  virtual void dance() { Grasshopper::dance(); }
  virtual void sing() { Grasshopper::sing(); }
</PRE>
</UL><A NAME="8072"></A>
<UL><PRE>protected:
  virtual void danceCustomization1();
  virtual void danceCustomization2();
</PRE>
</UL><A NAME="8073"></A>
<UL><PRE>  virtual void singCustomization();
};
</PRE>
</UL><A NAME="8074"></A>
<P><A NAME="dingp51"></A>
This seems to work fine. When a <CODE>Cricket</CODE> object is told to dance, it will execute the common <CODE>dance</CODE> code in the <CODE>Grasshopper</CODE> class, then execute the <CODE>dance</CODE> customization code in the <CODE>Cricket</CODE> class, then continue with the code in <CODE>Grasshopper::dance</CODE>, <NOBR>etc.<SCRIPT>create_link(51);</SCRIPT>
</NOBR></P>
<A NAME="8076"></A>
<P><A NAME="dingp52"></A>
There is a serious flaw in your design, however, and that is that you have run headlong into Occam's razor, a bad idea with a razor of any kind, and especially so when it belongs to William of Occam. Occamism preaches that entities should not be multiplied beyond necessity, <A NAME="p208"></A>and in this case, the entities in question are inheritance relationships. If you believe that multiple inheritance is more complicated than single inheritance (and I hope that you do), then the design of the <CODE>Cricket</CODE> class is needlessly <NOBR>complex.<SCRIPT>create_link(52);</SCRIPT>
</NOBR></P>
<A NAME="8078"></A>
<P><A NAME="dingp53"></A>
Fundamentally, the problem is that it is <i>not</i> true that the <CODE>Cricket</CODE> class is-implemented-in-terms-of the <CODE>Grasshopper</CODE> class. Rather, the <CODE>Cricket</CODE> class and the <CODE>Grasshopper</CODE> class <I>share common code</I>. In particular, they share the code that determines the dancing and singing behavior that grasshoppers and crickets have in <NOBR>common.<SCRIPT>create_link(53);</SCRIPT>
</NOBR></P>
<A NAME="8080"></A>
<P><A NAME="dingp54"></A>
The way to say that two classes have something in common is not to have one class inherit from the other, but to have <I>both</I> of them inherit from a common base class. The common code for grasshoppers and crickets doesn't belong in the <CODE>Grasshopper</CODE> class, nor does it belong in the <CODE>Cricket</CODE> class. It belongs in a new class from which they both inherit, say, <CODE>Insect</CODE>:<SCRIPT>create_link(54);</SCRIPT>
</P>
<A NAME="8081"></A>
<UL><PRE>class CartoonCharacter { ... };
</PRE>
</UL><A NAME="8083"></A>
<UL><PRE>class Insect: public CartoonCharacter {
public:
  virtual void dance();    // common code for both
  virtual void sing();     // grasshoppers and crickets
</PRE>
</UL><A NAME="8084"></A>
<UL><PRE>protected:
  virtual void danceCustomization1() = 0;
  virtual void danceCustomization2() = 0;
</PRE>
</UL><A NAME="8085"></A>
<UL><PRE>  virtual void singCustomization() = 0;
};
</PRE>
</UL><A NAME="8087"></A>
<UL><PRE>class Grasshopper: public Insect {
protected:
  virtual void danceCustomization1();
  virtual void danceCustomization2();
</PRE>
</UL><A NAME="8088"></A>
<UL><PRE>  virtual void singCustomization();
};
</PRE>
</UL><A NAME="8090"></A>
<UL><PRE>class Cricket: public Insect {
protected:
  virtual void danceCustomization1();
  virtual void danceCustomization2();
</PRE>
</UL><A NAME="8091"></A>
<UL><PRE>  virtual void singCustomization();
};
</PRE>
</UL><A NAME="8102"></A>
<A NAME="p209"></A>
<SPAN ID="Image6of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_208A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_208A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_208A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_208A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_208A5.GIF" BORDER=0></SPAN>

<SPAN ID="Image6of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_208A5.GIF" BORDER=0></SPAN>

<P><A NAME="dingp55"></A><A NAME="p209"></A><A NAME="8103"></A>Notice how much cleaner this design is. Only single inheritance is involved, and furthermore, only <I>public</I> inheritance is used. <CODE>Grasshopper</CODE> and <CODE>Cricket</CODE> define only customization functions; they inherit the <CODE>dance</CODE> and <CODE>sing</CODE> functions unchanged from <CODE>Insect</CODE>. William of Occam would be <NOBR>proud.<SCRIPT>create_link(55);</SCRIPT>
</NOBR></P>

<P><A NAME="dingp56"></A><A NAME="8106"></A>
Although this design is cleaner than the one involving MI, it may initially have appeared to be inferior. After all, compared to the MI approach, this single-inheritance architecture calls for the introduction of a brand new class, a class unnecessary if MI is used. Why introduce an extra class if you don't have <NOBR>to?<SCRIPT>create_link(56);</SCRIPT>
</NOBR></P>
<A NAME="8108"></A>
<P><A NAME="dingp57"></A>
This brings you face to face with the seductive nature of multiple inheritance. On the surface, MI seems to be the easier course of action. It adds no new classes, and though it calls for the addition of some new virtual functions to the <CODE>Grasshopper</CODE> class, those functions have to be added somewhere in any <NOBR>case.<SCRIPT>create_link(57);</SCRIPT>
</NOBR></P>
<A NAME="8109"></A>
<P><A NAME="dingp58"></A>
Imagine now a programmer maintaining a large C++ class library, one in which a new class has to be added, much as the <CODE>Cricket</CODE> class had to be added to the existing <CODE>CartoonCharacter</CODE>/<CODE>Grasshopper</CODE> hierarchy. The programmer knows that a large number of clients use the existing hierarchy, so the bigger the change to the library, the greater the disruption to clients. The programmer is determined to minimize that kind of disruption. Mulling over the options, the programmer realizes that if a single private inheritance link from <CODE>Grasshopper</CODE> to <CODE>Cricket</CODE> is added, no other change to the hierarchy will be needed. The programmer smiles at the thought, pleased with the prospect of a large increase in functionality at the cost of only a slight increase in <NOBR>complexity.<SCRIPT>create_link(58);</SCRIPT>
</NOBR></P>
<A NAME="8111"></A>
<P><A NAME="dingp59"></A>
Imagine now that that maintenance programmer is you. Resist the <NOBR>seduction.<SCRIPT>create_link(59);</SCRIPT>
</NOBR></P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI42_FR.HTM" TARGET="_top">Item 42: Use private inheritance judiciously.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI44_FR.HTM" TARGET="_top">Item 44: Say what you mean; understand what you're saying.</A></FONT></DIV>

</BODY>
</HTML>

⌨️ 快捷键说明

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