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

📄 ch13.htm

📁 good book for learning c++ standard language
💻 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://petunia.atomki.hu/pio/Manuals/english/0-672/0-672-31070-8/htm/ch12.htm"><IMG SRC="../buttons/BLANPREV.GIF" tppabs="http://petunia.atomki.hu/pio/Manuals/english/0-672/0-672-31070-8/buttons/BLANPREV.GIF"
WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A><A HREF="javascript:if(confirm('http://www.mcp.com/sams  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://www.mcp.com/sams'" tppabs="http://www.mcp.com/sams"><IMG
SRC="../buttons/BLANHOME.GIF" tppabs="http://petunia.atomki.hu/pio/Manuals/english/0-672/0-672-31070-8/buttons/BLANHOME.GIF" WIDTH="37" HEIGHT="37" ALIGN="BOTTOM"
BORDER="0"></A><A HREF="../index.htm" tppabs="http://petunia.atomki.hu/pio/Manuals/english/0-672/0-672-31070-8/index.htm"><IMG SRC="../buttons/BLANTOC.GIF" tppabs="http://petunia.atomki.hu/pio/Manuals/english/0-672/0-672-31070-8/buttons/BLANTOC.GIF"
WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A><A HREF="ch14.htm" tppabs="http://petunia.atomki.hu/pio/Manuals/english/0-672/0-672-31070-8/htm/ch14.htm"><IMG SRC="../buttons/BLANNEXT.GIF" tppabs="http://petunia.atomki.hu/pio/Manuals/english/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. This
is the fundamental building block of polymorphism: the capability to bind specific,
derived class objects to base class pointers at runtime. Today, you learnWhat multiple
inheritance 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 Single
Inheritance</FONT></H3>
<P>Suppose you've been working with your animal classes for a while and you've divided
the class hierarchy into <TT>Birds</TT> and <TT>Mammals</TT>. The <TT>Bird</TT> class
includes the member function <TT>Fly()</TT>. The <TT>Mammal</TT> class has been divided
into 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 able
to <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 cost
of 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 developer
who comes along months or years later to maintain your code must also know to fix
both 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 to
a 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);
else
gallop(distance);
}
</FONT></PRE>
<P>This is a bit limiting. Perhaps one day <TT>Pegasus</TT> will want to fly a short
distance 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 most
horses 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 horses
could fly...</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1:     // Listing 13.1. If horses could fly...
2:     // Percolating Fly() up into Horse
3:
4:     #include &lt;iostream.h&gt;
5:
6:     class Horse
7:     {
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 Horse
16:    {
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:          else
34:             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: 1

Horses 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-world
class, 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; represented
here by printing a happy message.</P>
<P>The array of <TT>Horse</TT> pointers on line 24 is used to demonstrate that the
correct <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 solution
to this problem and results in many functions &quot;percolating up&quot; into the
base class. The base class is then in grave danger of becoming a global namespace
for all the functions that might be used by any of the derived classes. This can
seriously undermine the class typing of C++, and can create a large and cumbersome
base class.</P>
<P>In general, you want to percolate shared functionality up the hierarchy, without
migrating the interface of each class. This means that if two classes that share
a 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 to
move 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 derived
classes.
<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 is
actually pointing to a <TT>Pegasus</TT> object. To make this work, you'll need to
be able to ask your pointer what type it is really pointing to. This is known as
Run Time Type Identification (RTTI). Using RTTI has only recently become an official
part of C++.</P>
<P>If your compiler does not support RTTI, you can mimic it by putting a method that
returns an enumerated type in each of the classes. You can then test that type at
runtime 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 it
that 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 down
to a more derived type.</P>
<P>C++ now officially, though perhaps reluctantly, supports casting down using the
new <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 to
it 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> operator
to make the conversion.</P>
<P>At runtime, the base pointer will be examined. If the conversion is proper, your
new <TT>Pegasus</TT> pointer will be fine. If the conversion is improper, if you
didn't really have a <TT>Pegasus</TT> object after all, then your new pointer will
be null. Listing 13.2 illustrates this point.</P>
<P><A NAME="Heading8"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.2. Casting
down.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1:     // Listing 13.2 Using dynamic_cast.
2:     // Using rtti
3:
4:     #include &lt;iostream.h&gt;
5:     enum TYPE { HORSE, PEGASUS };
6:
7:     class Horse
8:     {
9:     public:
10:       virtual void Gallop(){ cout &lt;&lt; &quot;Galloping...\n&quot;; }
11:       

⌨️ 快捷键说明

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