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

📄 ch13.htm

📁 一本好的VC学习书,本人就是使用这本书开始学习的vc,希望能对大家有帮助
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD><!-- This document was created from RTF source by rtftohtml version 3.0.1 -->	<META NAME="GENERATOR" Content="Symantec Visual Page 1.0">	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">	<TITLE>Teach Yourself C++ in 21 Days</TITLE></HEAD><BODY TEXT="#000000" BGCOLOR="#FFFFFF"><H1 ALIGN="CENTER"><A HREF="ch12.htm" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/htm/ch12.htm"><IMG SRC="BLANPREV.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANPREV.GIF"WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A><A HREF="tppmsgs/msgs0.htm#1" tppabs="http://www.mcp.com/sams"><IMGSRC="BLANHOME.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANHOME.GIF" WIDTH="37" HEIGHT="37" ALIGN="BOTTOM"BORDER="0"></A><A HREF="index.htm" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/index.htm"><IMG SRC="BLANTOC.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANTOC.GIF"WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A><A HREF="ch14.htm" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/htm/ch14.htm"><IMG SRC="BLANNEXT.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANNEXT.GIF"WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A></H1><H1></H1><UL>	<LI><A HREF="#Heading1">Day 13</A>	<UL>		<LI><A HREF="#Heading2">Polymorphism</A>		<UL>			<LI><A HREF="#Heading3">Problems with Single Inheritance</A>			<LI><A HREF="#Heading4">Listing 13.1. If horses could fly</A><A HREF="#Heading5">...</A>			<UL>				<LI><A HREF="#Heading6">Percolating Upward</A>				<LI><A HREF="#Heading7">Casting Down</A>			</UL>			<LI><A HREF="#Heading8">Listing 13.2. Casting down</A><A HREF="#Heading9">.</A>			<UL>				<LI><A HREF="#Heading10">Adding to Two Lists</A>			</UL>			<LI><A HREF="#Heading11">Multiple Inheritance</A>			<LI><A HREF="#Heading12">Listing 13.3. Multiple inheritance</A><A HREF="#Heading13">.</A>			<LI><A HREF="#Heading14">Declaring Multiple Inheritance</A>			<UL>				<LI><A HREF="#Heading15">The Parts of a Multiply Inherited Object</A>				<UL>					<LI><A HREF="#Heading16">Figure 13.1.</A>				</UL>				<LI><A HREF="#Heading17">Constructors in Multiply Inherited Objects</A>			</UL>			<LI><A HREF="#Heading18">Listing 13.4. Calling multiple constructors</A><A HREF="#Heading19">.</A>			<UL>				<LI><A HREF="#Heading20">Ambiguity Resolution</A>				<LI><A HREF="#Heading21">Inheriting from Shared Base Class</A>				<UL>					<LI><A HREF="#Heading22">Figure 13.2.</A>				</UL>			</UL>			<LI><A HREF="#Heading23">Listing 13.5. Common base classes</A><A HREF="#Heading24">.</A>			<UL>				<LI><A HREF="#Heading25">Virtual Inheritance</A>				<UL>					<LI><A HREF="#Heading26">Figure 13.3.</A>				</UL>			</UL>			<LI><A HREF="#Heading27">Listing 13.6. Illustration of the use of virtual inheritance</A><A			HREF="#Heading28">.</A>			<LI><A HREF="#Heading29">Declaring Classes for Virtual Inheritance</A>			<UL>				<LI><A HREF="#Heading30">Problems with Multiple Inheritance</A>				<LI><A HREF="#Heading31">Mixins and Capabilities Classes</A>			</UL>			<LI><A HREF="#Heading32">Abstract Data Types</A>			<LI><A HREF="#Heading33">Listing 13.7. Shape classes</A><A HREF="#Heading34">.</A>			<UL>				<LI><A HREF="#Heading35">Pure Virtual Functions</A>			</UL>			<LI><A HREF="#Heading36">Listing 13.8. Abstract Data Types</A><A HREF="#Heading37">.</A>			<LI><A HREF="#Heading38">Abstract Data Types</A>			<UL>				<LI><A HREF="#Heading39">Implementing Pure Virtual Functions</A>			</UL>			<LI><A HREF="#Heading40">Listing 13.9. Implementing pure virtual functions</A><A			HREF="#Heading41">.</A>			<UL>				<LI><A HREF="#Heading42">Complex Hierarchies of Abstraction</A>			</UL>			<LI><A HREF="#Heading43">Listing 13.10. Deriving ADTs from other ADTs</A><A HREF="#Heading44">.</A>			<UL>				<LI><A HREF="#Heading45">Which Types Are Abstract?</A>			</UL>			<LI><A HREF="#Heading46">The Observer Pattern</A>			<UL>				<LI><A HREF="#Heading47">A Word About Multiple Inheritance, Abstract Data Types,				and Java</A>			</UL>			<LI><A HREF="#Heading48">Summary</A>			<LI><A HREF="#Heading49">Q&amp;A</A>			<LI><A HREF="#Heading50">Workshop</A>			<UL>				<LI><A HREF="#Heading51">Quiz</A>				<LI><A HREF="#Heading52">Exercises</A>			</UL>		</UL>	</UL></UL><P><HR SIZE="4"><H2 ALIGN="CENTER"><A NAME="Heading1"></A><FONT COLOR="#000077">Day 13</FONT></H2><H2 ALIGN="CENTER"><A NAME="Heading2"></A><FONT COLOR="#000077">Polymorphism</FONT></H2><P>Yesterday, you learned how to write virtual functions in derived classes. Thisis the fundamental building block of polymorphism: the capability to bind specific,derived class objects to base class pointers at runtime. Today, you learnWhat multipleinheritance is and how to use it.<UL>	<LI>What virtual inheritance is.	<P>	<LI>What abstract data types are.	<P>	<LI>What pure virtual functions are.</UL><H3 ALIGN="CENTER"><A NAME="Heading3"></A><FONT COLOR="#000077">Problems with SingleInheritance</FONT></H3><P>Suppose you've been working with your animal classes for a while and you've dividedthe class hierarchy into <TT>Birds</TT> and <TT>Mammals</TT>. The <TT>Bird</TT> classincludes the member function <TT>Fly()</TT>. The <TT>Mammal</TT> class has been dividedinto a number of types of <TT>Mammal</TT>s, including <TT>Horse</TT>. The <TT>Horse</TT>class includes the member functions <TT>Whinny()</TT> and <TT>Gallop()</TT>.</P><P>Suddenly, you realize you need a <TT>Pegasus</TT> object: a cross between a <TT>Horse</TT>and a <TT>Bird</TT>. A <TT>Pegasus</TT> can <TT>Fly()</TT>, it can <TT>Whinny()</TT>,and it can <TT>Gallop()</TT>. With single inheritance, you're in quite a jam.</P><P>You can make <TT>Pegasus</TT> a <TT>Bird</TT>, but then it won't be able to <TT>Whinny()</TT>or <TT>Gallop()</TT>. You can make it a <TT>Horse</TT>, but then it won't be ableto <TT>Fly()</TT>.</P><P>Your first solution is to copy the <TT>Fly()</TT> method into the <TT>Pegasus</TT>class and derive <TT>Pegasus</TT> from <TT>Horse</TT>. This works fine, at the costof having the <TT>Fly()</TT> method in two places (<TT>Bird</TT> and <TT>Pegasus</TT>).If you change one, you must remember to change the other. Of course, a developerwho comes along months or years later to maintain your code must also know to fixboth places.</P><P>Soon, however, you have a new problem. You wish to create a list of <TT>Horse</TT>objects and a list of <TT>Bird</TT> objects. You'd like to be able to add your <TT>Pegasus</TT>objects to either list, but if a <TT>Pegasus</TT> is a horse, you can't add it toa list of birds.</P><P>You have a couple of potential solutions. You can rename the <TT>Horse</TT> method<TT>Gallop()</TT> to <TT>Move()</TT>, and then override <TT>Move()</TT> in your <TT>Pegasus</TT>object to do the work of <TT>Fly()</TT>. You would then override <TT>Move()</TT>in your other horses to do the work of <TT>Gallop()</TT>. Perhaps <TT>Pegasus</TT>could be clever enough to gallop short distances and fly longer distances.</P><PRE><FONT COLOR="#0066FF">Pegasus::Move(long distance){if (distance &gt; veryFar)fly(distance);elsegallop(distance);}</FONT></PRE><P>This is a bit limiting. Perhaps one day <TT>Pegasus</TT> will want to fly a shortdistance or gallop a long distance. Your next solution might be to move <TT>Fly()</TT>up into <TT>Horse</TT>, as illustrated in Listing 13.1. The problem is that mosthorses can't fly, so you have to make this method do nothing unless it is a <TT>Pegasus</TT>.</P><P><A NAME="Heading4"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.1. If horsescould fly...</B></FONT></P><PRE><FONT COLOR="#0066FF">1:     // Listing 13.1. If horses could fly...2:     // Percolating Fly() up into Horse3:4:     #include &lt;iostream.h&gt;5:6:     class Horse7:     {8:     public:9:        void Gallop(){ cout &lt;&lt; &quot;Galloping...\n&quot;; }10:       virtual void Fly() { cout &lt;&lt; &quot;Horses can't fly.\n&quot; ; }11:    private:12:       int itsAge;13:    };14:15:    class Pegasus : public Horse16:    {17:    public:18:       virtual void Fly() { cout &lt;&lt; &quot;I can fly! I can fly! I can fly!\n&quot;; }19:    };20:21:    const int NumberHorses = 5;22:    int main()23:    {24:       Horse* Ranch[NumberHorses];25:       Horse* pHorse;26:       int choice,i;27:       for (i=0; i&lt;NumberHorses; i++)28:       {29:          cout &lt;&lt; &quot;(1)Horse (2)Pegasus: &quot;;30:          cin &gt;&gt; choice;31:          if (choice == 2)32:             pHorse = new Pegasus;33:          else34:             pHorse = new Horse;35:          Ranch[i] = pHorse;36:       }37:       cout &lt;&lt; &quot;\n&quot;;38:       for (i=0; i&lt;NumberHorses; i++)39:       {40:          Ranch[i]-&gt;Fly();41:          delete Ranch[i];42:       }43:     return 0;<TT>44: }</TT></FONT><FONT COLOR="#0066FF">Output: (1)Horse (2)Pegasus: 1(1)Horse (2)Pegasus: 2(1)Horse (2)Pegasus: 1(1)Horse (2)Pegasus: 2(1)Horse (2)Pegasus: 1Horses can't fly.I can fly! I can fly! I can fly!Horses can't fly.I can fly! I can fly! I can fly!Horses can't fly. </FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>This program certainly works,though at the expense of the <TT>Horse</TT> class having a <TT>Fly()</TT> method.On line 10, the method<TT> Fly()</TT> is provided to <TT>Horse</TT>. In a real-worldclass, you might have it issue an error, or fail quietly. On line 18, the <TT>Pegasus</TT>class overrides the <TT>Fly()</TT> method to &quot;do the right thing,&quot; representedhere by printing a happy message.</P><P>The array of <TT>Horse</TT> pointers on line 24 is used to demonstrate that thecorrect <TT>Fly()</TT> method is called based on the runtime binding of the <TT>Horse</TT>or <TT>Pegasus</TT> object.<H4 ALIGN="CENTER"><A NAME="Heading6"></A><FONT COLOR="#000077">Percolating Upward</FONT></H4><P>Putting the required function higher in the class hierarchy is a common solutionto this problem and results in many functions &quot;percolating up&quot; into thebase class. The base class is then in grave danger of becoming a global namespacefor all the functions that might be used by any of the derived classes. This canseriously undermine the class typing of C++, and can create a large and cumbersomebase class.</P><P>In general, you want to percolate shared functionality up the hierarchy, withoutmigrating the interface of each class. This means that if two classes that sharea common base class (for example, <TT>Horse</TT> and <TT>Bird</TT> both share <TT>Animal</TT>)have a function in common (both birds and horses eat, for example), you'll want tomove that functionality up into the base class and create a virtual function.</P><P>What you'll want to avoid, however, is percolating an interface (like <TT>Fly</TT>up where it doesn't belong), just so you can call that function only on some derivedclasses.<H4 ALIGN="CENTER"><A NAME="Heading7"></A><FONT COLOR="#000077">Casting Down</FONT></H4><P>An alternative to this approach, still within single inheritance, is to keep the<TT>Fly()</TT> method within <TT>Pegasus</TT>, and only call it if the pointer isactually pointing to a <TT>Pegasus</TT> object. To make this work, you'll need tobe able to ask your pointer what type it is really pointing to. This is known asRun Time Type Identification (RTTI). Using RTTI has only recently become an officialpart of C++.</P><P>If your compiler does not support RTTI, you can mimic it by putting a method thatreturns an enumerated type in each of the classes. You can then test that type atruntime and call <TT>Fly()</TT> if it returns <TT>Pegasus</TT>.<BLOCKQUOTE>	<P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>Beware of adding RTTI to your classes.	Use of it may be an indication of poor design. Consider using virtual functions,	templates, or multiple inheritance instead. <HR></BLOCKQUOTE><P>In order to call <TT>Fly()</TT> however, you must cast the pointer, telling itthat the object it is pointing to is a <TT>Pegasus</TT> object, not a <TT>Horse</TT>.This is called casting down, because you are casting the <TT>Horse</TT> object downto a more derived type.</P><P>C++ now officially, though perhaps reluctantly, supports casting down using thenew <TT>dynamic_cast</TT> operator. Here's how it works.</P><P>If you have a pointer to a base class such as <TT>Horse</TT>, and you assign toit a pointer to a derived class, such as <TT>Pegasus</TT>, you can use the <TT>Horse</TT>pointer polymorphically. If you then need to get at the <TT>Pegasus</TT> object,you create a <TT>Pegasus</TT> pointer and use the <TT>dynamic_cast</TT> operatorto make the conversion.</P><P>At runtime, the base pointer will be examined. If the conversion is proper, yournew <TT>Pegasus</TT> pointer will be fine. If the conversion is improper, if youdidn't really have a <TT>Pegasus</TT> object after all, then your new pointer willbe null. Listing 13.2 illustrates this point.</P><P><A NAME="Heading8"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.2. Castingdown.</B></FONT></P><PRE><FONT COLOR="#0066FF">1:     // Listing 13.2 Using dynamic_cast.2:     // Using rtti3:4:     #include &lt;iostream.h&gt;5:     enum TYPE { HORSE, PEGASUS };6:7:     class Horse8:     {9:     public:10:       virtual void Gallop(){ cout &lt;&lt; &quot;Galloping...\n&quot;; }11:       12:    private:13:       int itsAge;14:    };15:16:    class Pegasus : public Horse17:    {18:    public:19:       20:       virtual void Fly() { cout &lt;&lt; &quot;I can fly! I can fly! I can fly!\n&quot;; }21:    };22:23:    const int NumberHorses = 5;24:    int main()

⌨️ 快捷键说明

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