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

📄 ei43.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<title>Effective C++, 2E | Item 43</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 7; setCurrentMax(7);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/IMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/NSIMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var dingbase = "EI43_DIR.HTM"; var dingtext =
"Item E43, P"; if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E43: Use multiple inheritance judiciously" -->

<A NAME="7778"></A>
<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>

<P><A NAME="dingp1"></A><FONT ID="eititle">Item 43: &nbsp;Use multiple inheritance judiciously.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="7781"></A>
<P><A NAME="dingp2"></A>
Depending on who's doing the talking, multiple inheritance (MI) is either the product of divine inspiration or the manifest work of the devil. <A NAME="p195"></A>Proponents hail it as essential to the natural modeling of real-world problems, while critics argue that it is slow, difficult to implement, and no more powerful than single inheritance. Disconcertingly, the world of object-oriented programming languages remains split on the issue: C++, Eiffel, and the Common LISP Object System (CLOS) offer MI; Smalltalk, Objective C, and Object Pascal do not; and Java supports only a restricted form of it. What's a poor, struggling programmer to <NOBR>believe?<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="7788"></A>
<P><A NAME="dingp3"></A>
Before you believe anything, you need to get your facts straight. The one indisputable fact about MI in C++ is that it opens up a Pandora's box of complexities that simply do not exist under single inheritance. Of these, the most basic is ambiguity (see <A HREF="./EI26_FR.HTM#6337" TARGET="_top">Item 26</A>). If a derived class inherits a member name from more than one base class, any reference to that name is ambiguous; you must explicitly say which member you mean. Here's an example that's based on a discussion in the ARM (see <A HREF="./EI50_FR.HTM#8569" TARGET="_top">Item 50</A>):<SCRIPT>create_link(3);</SCRIPT>
</P>
<A NAME="7799"></A>
<UL><PRE>class Lottery {
public:
  virtual int draw();
</PRE>
</UL><A NAME="7800"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="7801"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7803"></A>
<UL><PRE>class GraphicalObject {
public:
  virtual int draw();
</PRE>
</UL><A NAME="7804"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="7805"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7807"></A>
<UL><PRE>
class LotterySimulation: public Lottery,
                         public GraphicalObject {
</PRE>
</UL><A NAME="7808"></A>
<UL><PRE>
  ...                          // doesn't declare draw
</PRE>
</UL><A NAME="7809"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7810"></A>
<UL><PRE>LotterySimulation *pls = new LotterySimulation;
</PRE>
</UL><A NAME="7811"></A>
<UL><PRE>
pls-&gt;draw();                   // error! &#151; ambiguous
pls-&gt;Lottery::draw();          // fine
pls-&gt;GraphicalObject::draw();  // fine
</PRE>
</UL><A NAME="7812"></A>
<P><A NAME="dingp4"></A>
This looks clumsy, but at least it works. Unfortunately, the clumsiness is difficult to eliminate. Even if one of the inherited <CODE>draw</CODE> functions were private and hence inaccessible, the ambiguity would remain. (There's a good reason for that, but a complete explanation of the situation is provided in <A HREF="./EI26_FR.HTM#6337" TARGET="_top">Item 26</A>, so I won't repeat it <NOBR>here.)<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<A NAME="7816"></A>
<P><A NAME="dingp5"></A>
<A NAME="p196"></A>Explicitly qualifying members is more than clumsy, however, it's also limiting. When you explicitly qualify a virtual function with a class name, the function doesn't act virtual any longer. Instead, the function called is precisely the one you specify, even if the object on which it's invoked is of a derived <NOBR>class:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="7819"></A>
<UL><PRE>class SpecialLotterySimulation: public LotterySimulation {
public:
  virtual int draw();
</PRE>
</UL><A NAME="7820"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="7821"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7822"></A>
<UL><PRE>pls = new SpecialLotterySimulation;
</PRE>
</UL><A NAME="7823"></A>
<UL><PRE>
pls-&gt;draw();                        // error! &#151; still ambiguous
pls-&gt;Lottery::draw();               // calls Lottery::draw
pls-&gt;GraphicalObject::draw();       // calls GraphicalObject::draw
</PRE>
</UL><A NAME="7824"></A>
<P><A NAME="dingp6"></A>
In this case, notice that even though <CODE>pls</CODE> points to a <CODE>SpecialLotterySimulation</CODE> object, there is no way (short of a downcast &#151; see <A HREF="./EI39_FR.HTM#7269" TARGET="_top">Item 39</A>) to invoke the <CODE>draw</CODE> function defined in that <NOBR>class.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="7830"></A>
<P><A NAME="dingp7"></A>
But wait, there's more. The <CODE>draw</CODE> functions in both <CODE>Lottery</CODE> and <CODE>GraphicalObject</CODE> are declared virtual so that subclasses can redefine them (see <A HREF="./EI36_FR.HTM#7007" TARGET="_top">Item 36</A>), but what if <CODE>LotterySimulation</CODE> would like to redefine <i>both</i> of them? The unpleasant truth is that it can't, because a class is allowed to have only a single function called <CODE>draw</CODE> that takes no arguments. (There is a special exception to this rule if one of the functions is <CODE>const</CODE> and one is not &#151; see <A HREF="./EI21_FR.HTM#6003" TARGET="_top">Item 21</A>.)<SCRIPT>create_link(7);</SCRIPT>
</P>
<A NAME="7838"></A>
<P><A NAME="dingp8"></A>
At one point, this difficulty was considered a serious enough problem to justify a change in the language. The ARM discusses the possibility of allowing inherited virtual functions to be "renamed," but then it was discovered that the problem can be circumvented by the addition of a pair of new <NOBR>classes:<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="7841"></A>
<UL><PRE>class AuxLottery: public Lottery {
public:
  virtual int lotteryDraw() = 0;
</PRE>
</UL><A NAME="7842"></A>
<UL><PRE>  virtual int draw() { return lotteryDraw(); }
};
</PRE>
</UL><A NAME="7844"></A>
<UL><PRE>class AuxGraphicalObject: public GraphicalObject {
public:
  virtual int graphicalObjectDraw() = 0;
</PRE>
</UL><A NAME="7845"></A>
<UL><PRE>  virtual int draw() { return graphicalObjectDraw(); }
};
</PRE>
</UL><A NAME="7847"></A>
<UL><PRE><A NAME="p197"></A>
class LotterySimulation: public AuxLottery,
                         public AuxGraphicalObject {
public:
  virtual int lotteryDraw();
  virtual int graphicalObjectDraw();
</PRE>
</UL><A NAME="7848"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="7849"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="7850"></A>
<A NAME="dingp9"></A>Each of the two new classes, <CODE>AuxLottery</CODE> and <CODE>AuxGraphicalObject</CODE>, essentially declares a new name for the <CODE>draw</CODE> function that each inherits. This new name takes the form of a pure virtual function, in this case <CODE>lotteryDraw</CODE> and <CODE>graphicalObjectDraw</CODE>; the functions are pure virtual so that concrete subclasses must redefine them. Furthermore, each class redefines the <CODE>draw</CODE> that it inherits to itself invoke the new pure virtual function. The net effect is that within this class hierarchy, the single, ambiguous name <CODE>draw</CODE> has effectively been split into two unambiguous, but operationally equivalent, names: <CODE>lotteryDraw</CODE> and <CODE>graphicalObjectDraw</CODE>:<SCRIPT>create_link(9);</SCRIPT>
</P>
<A NAME="7852"></A>
<UL><PRE>LotterySimulation *pls = new LotterySimulation;
</PRE>
</UL><A NAME="7853"></A>
<UL><PRE>Lottery *pl = pls;
GraphicalObject *pgo = pls;
</PRE>
</UL><A NAME="7854"></A>
<UL><PRE>// this calls LotterySimulation::lotteryDraw
pl-&gt;draw();
</PRE>
</UL><A NAME="7855"></A>
<UL><PRE>// this calls LotterySimulation::graphicalObjectDraw
pgo-&gt;draw();
</PRE>
</UL><A NAME="7856"></A>
<P><A NAME="dingp10"></A>
This strategy, replete as it is with the clever application of pure virtual, simple virtual, and inline functions (see <A HREF="./EI33_FR.HTM#6729" TARGET="_top">Item 33</A>), should be committed to memory. In the first place, it solves a problem that you may encounter some day. In the second, it can serve to remind you of the complications that can arise in the presence of multiple inheritance. Yes, this tactic works, but do you really want to be forced to introduce new classes just so you can redefine a virtual function? The classes <CODE>AuxLottery</CODE> and <CODE>AuxGraphicalObject</CODE> are essential to the correct operation of this hierarchy, but they correspond neither to an abstraction in the problem domain nor to an abstraction in the implementation domain. They exist purely as an implementation device &#151; nothing more. You already know that good software is "device independent." That rule of thumb applies here, <NOBR>too.<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P>

<P><A NAME="dingp11"></A><A NAME="7858"></A>The ambiguity problem, interesting though it is, hardly begins to scratch the surface of the issues you'll confront when you flirt with MI. Another one grows out of the empirical observation that an inheritance <A NAME="p198"></A>hierarchy that starts out looking like <NOBR>this,<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>

<SPAN ID="Image1of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_198A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_198A2.GIF" BORDER=0></SPAN>

⌨️ 快捷键说明

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