📄 ch13.htm
字号:
25: {26: Horse* Ranch[NumberHorses];27: Horse* pHorse;28: int choice,i;29: for (i=0; i<NumberHorses; i++)30: {31: cout << "(1)Horse (2)Pegasus: ";32: cin >> choice;33: if (choice == 2)34: pHorse = new Pegasus;35: else36: pHorse = new Horse;37: Ranch[i] = pHorse;38: }39: cout << "\n";40: for (i=0; i<NumberHorses; i++)41: {42: Pegasus *pPeg = dynamic_cast< Pegasus *> (Ranch[i]);42: if (pPeg)43: pPeg->Fly();44: else45: cout << "Just a horse\n";46:47: delete Ranch[i];48: }49: return 0;<TT>50:</TT></FONT><TT></TT><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: 1Just a horseI can fly! I can fly! I can fly!Just a horseI can fly! I can fly! I can fly!Just a horse</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>This solution also works.<TT>Fly()</TT> is kept out of <TT>Horse</TT>, and is not called on <TT>Horse</TT>objects. When it is called on <TT>Pegasus</TT> objects, however, they must be explicitlycast; <TT>Horse</TT> objects don't have the method <TT>Fly()</TT>, so the pointermust be told it is pointing to a <TT>Pegasus</TT> object before being used.</P><P>The need for you to cast the <TT>Pegasus</TT> object is a warning that somethingmay be wrong with your design. This program effectively undermines the virtual functionpolymorphism, because it depends on casting the object to its real runtime type.<H4 ALIGN="CENTER"><A NAME="Heading10"></A><FONT COLOR="#000077">Adding to Two Lists</FONT></H4><P>The other problem with these solutions is that you've declared <TT>Pegasus</TT>to be a type of <TT>Horse</TT>, so you cannot add a <TT>Pegasus</TT> object to alist of <TT>Birds</TT>. You've paid the price of either moving <TT>Fly()</TT> upinto <TT>Horse</TT>, or casting down the pointer, and yet you still don't have thefull functionality you need.</P><P>One final single inheritance solution presents itself. You can push <TT>Fly()</TT>,<TT>Whinny()</TT>, and <TT>Gallop()</TT> all up into a common base class of both<TT>Bird</TT> and <TT>Horse</TT>: <TT>Animal</TT>. Now, instead of having a listof <TT>Bird</TT>s and a list of <TT>Horse</TT>s, you can have one unified list of<TT>Animal</TT>s. This works, but percolates more functionality up into the baseclasses.</P><P>Alternatively, you can leave the methods where they are, but cast down <TT>Horses</TT>and <TT>Birds</TT> and <TT>Pegasus</TT> objects, but that is even worse!<BLOCKQUOTE> <P><HR><B>DO</B> move functionality up the inheritance hierarchy. <B>DON'T</B> move interface up the inheritance hierarchy. <B>DO</B> avoid switching on the runtime type of the object--use virtual methods, templates, and multiple inheritance.<B> DON'T</B> cast pointers to base objects down to derived objects. <HR></BLOCKQUOTE><H3 ALIGN="CENTER"><A NAME="Heading11"></A><FONT COLOR="#000077">Multiple Inheritance</FONT></H3><P>It is possible to derive a new class from more than one base class. This is calledMultiple Inheritance. To derive from more than the base class, you separate eachbase class by commas in the class designation. Listing 13.3 illustrates how to declare<TT>Pegasus</TT> so that it derives from both <TT>Horses</TT> and <TT>Birds</TT>.The program then adds <TT>Pegasus</TT> objects to both types of lists.</P><P><A NAME="Heading12"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.3. Multipleinheritance.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 13.3. Multiple inheritance.2: // Multiple Inheritance3:4: #include <iostream.h>5:6: class Horse7: {8: public:9: Horse() { cout << "Horse constructor... "; }10: virtual ~Horse() { cout << "Horse destructor... "; }11: virtual void Whinny() const { cout << "Whinny!... "; }12: private:13: int itsAge;14: };15:16: class Bird17: {18: public:19: Bird() { cout << "Bird constructor... "; }20: virtual ~Bird() { cout << "Bird destructor... "; }21: virtual void Chirp() const { cout << "Chirp... "; }22: virtual void Fly() const 23: { 24: cout << "I can fly! I can fly! I can fly! "; 25: }26: private:27: int itsWeight;28: };29:30: class Pegasus : public Horse, public Bird31: {32: public:33: void Chirp() const { Whinny(); }34: Pegasus() { cout << "Pegasus constructor... "; }35: ~Pegasus() { cout << "Pegasus destructor... "; }36: };37:38: const int MagicNumber = 2;39: int main()40: {41: Horse* Ranch[MagicNumber];42: Bird* Aviary[MagicNumber];43: Horse * pHorse;44: Bird * pBird; 45: int choice,i;46: for (i=0; i<MagicNumber; i++)47: {48: cout << "\n(1)Horse (2)Pegasus: ";49: cin >> choice;50: if (choice == 2)51: pHorse = new Pegasus;52: else53: pHorse = new Horse;54: Ranch[i] = pHorse;55: }56: for (i=0; i<MagicNumber; i++)57: {58: cout << "\n(1)Bird (2)Pegasus: ";59: cin >> choice;60: if (choice == 2)61: pBird = new Pegasus; 62: else63: pBird = new Bird;64: Aviary[i] = pBird;65: }66:67: cout << "\n";68: for (i=0; i<MagicNumber; i++)69: {70: cout << "\nRanch[" << i << "]: " ;71: Ranch[i]->Whinny();72: delete Ranch[i];73: }74:75: for (i=0; i<MagicNumber; i++)76: {77: cout << "\nAviary[" << i << "]: " ;78: Aviary[i]->Chirp();79: Aviary[i]->Fly();80: delete Aviary[i];81: }82: return 0;<TT>83: }</TT></FONT><FONT COLOR="#0066FF">Output: (1)Horse (2)Pegasus: 1Horse constructor...(1)Horse (2)Pegasus: 2Horse constructor... Bird constructor... Pegasus constructor...(1)Bird (2)Pegasus: 1Bird constructor...(1)Bird (2)Pegasus: 2Horse constructor... Bird constructor... Pegasus constructor...Ranch[0]: Whinny!... Horse destructor...Ranch[1]: Whinny!... Pegasus destructor... Bird destructor... Horse destructor...Aviary[0]: Chirp... I can fly! I can fly! I can fly! Bird destructor...Aviary[1]: Whinny!... I can fly! I can fly! I can fly! Pegasus destructor... Bird destructor... Horse destructor...Aviary[0]: Chirp... I can fly! I can fly! I can fly! Bird destructor...Aviary[1]: Whinny!... I can fly! I can fly! I can fly! Pegasus destructor.. Bird destructor... Horse destructor... </FONT></PRE><P><FONT COLOR="#000077"><B>Analysis: </B></FONT>On lines 6-14, a <TT>Horse</TT>class is declared. The constructor and destructor print out a message, and the <TT>Whinny()</TT>method prints the word <TT>Whinny!</TT></P><P>On lines 16-25, a <TT>Bird</TT> class is declared. In addition to its constructorand destructor, this class has two methods: <TT>Chirp()</TT> and <TT>Fly()</TT>,both of which print identifying messages. In a real program these might, for example,activate the speaker or generate animated images.</P><P>Finally, on lines 30-36, the class <TT>Pegasus</TT> is declared. It derives bothfrom <TT>Horse</TT> and from <TT>Bird</TT>. The <TT>Pegasus</TT> class overridesthe <TT>Chirp()</TT> method to call the <TT>Whinny()</TT> method, which it inheritsfrom <TT>Horse</TT>.</P><P>Two lists are created, a <TT>Ranch</TT> with pointers to <TT>Horse</TT> on line41, and an <TT>Aviary</TT> with pointers to <TT>Bird</TT> on line 42. On lines 46-55,<TT>Horse</TT> and <TT>Pegasus</TT> objects are added to the <TT>Ranch</TT>. On lines56-65, <TT>Bird</TT> and <TT>Pegasus</TT> objects are added to the <TT>Aviary</TT>.</P><P>Invocations of the virtual methods on both the <TT>Bird</TT> pointers and the<TT>Horse</TT> pointers do the right things for <TT>Pegasus</TT> objects. For example,on line 78 the members of the <TT>Aviary</TT> array are used to call <TT>Chirp()</TT>on the objects to which they point. The <TT>Bird</TT> class declares this to be avirtual method, so the right function is called for each object.</P><P>Note that each time a <TT>Pegasus</TT> object is created, the output reflectsthat both the <TT>Bird</TT> part and the <TT>Horse</TT> part of the <TT>Pegasus</TT>object is also created. When a <TT>Pegasus</TT> object is destroyed, the <TT>Bird</TT>and <TT>Horse</TT> parts are destroyed as well, thanks to the destructors being madevirtual.<H3 ALIGN="CENTER"><A NAME="Heading14"></A><FONT COLOR="#000077">Declaring MultipleInheritance</FONT></H3><P>Declare an object to inherit from more than one class by listing the base classesfollowing the colon after the class name. Separate the base classes by commas. Example1:</P><PRE><FONT COLOR="#0066FF">class Pegasus : public Horse, public Bird</FONT></PRE><P>Example 2:</P><PRE><FONT COLOR="#0066FF">class Schnoodle : public Schnauzer, public Poodle</FONT></PRE><H4 ALIGN="CENTER"><A NAME="Heading15"></A><FONT COLOR="#000077">The Parts of a MultiplyInherited Object</FONT></H4><P>When the <TT>Pegasus</TT> object is created in memory, both of the base classesform part of the <TT>Pegasus</TT> object, as illustrated in Figure 13.1.<BR><BR><A NAME="Heading16"></A><A HREF="13zcp01.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch13/13zcp01.jpg"><FONT COLOR="#000077">Figure13.1.</FONT></A><FONT COLOR="#000077"> </FONT><I>Multiply inherited objects.</I><BR><BR>A number of issues arise with objects with multiple base classes. For example, whathappens if two base classes that happen to have the same name have virtual functionsor data? How are multiple base class constructors initialized? What happens if multiplebase classes both derive from the same class? The next sections will answer thesequestions, and explore how multiple inheritance can be put to work.<H4 ALIGN="CENTER"><A NAME="Heading17"></A><FONT COLOR="#000077">Constructors inMultiply Inherited Objects</FONT></H4><P>If <TT>Pegasus</TT> derives from both <TT>Horse</TT> and <TT>Bird</TT>, and eachof the base classes has constructors that take parameters, the <TT>Pegasus</TT> classinitializes these constructors in turn. Listing 13.4 illustrates how this is done.</P><P><A NAME="Heading18"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.4. Callingmultiple constructors.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 13.42: // Calling multiple constructors3: #include <iostream.h>4: typedef int HANDS;5: enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;6: enum BOOL { FALSE, TRUE };7:8: class Horse9: {10: public:11: Horse(COLOR color, HANDS height);12: virtual ~Horse() { cout << "Horse destructor...\n"; }13: virtual void Whinny()const { cout << "Whinny!... "; }14: virtual HANDS GetHeight() const { return itsHeight; }15: virtual COLOR GetColor() const { return itsColor; }16: private:17: HANDS itsHeight;18: COLOR itsColor;19: };20:21: Horse::Horse(COLOR color, HANDS height):22: itsColor(color),itsHeight(height)23: {24: cout << "Horse constructor...\n";25: }26:27: class Bird28: {29: public:30: Bird(COLOR color, BOOL migrates);31: virtual ~Bird() {cout << "Bird destructor...\n"; }32: virtual void Chirp()const { cout << "Chirp... "; }33: virtual void Fly()const 34: { 35: cout << "I can fly! I can fly! I can fly! "; 36: }37: virtual COLOR GetColor()const { return itsColor; }38: virtual BOOL GetMigration() const { return itsMigration; }39: 40: private:41: COLOR itsColor;42: BOOL itsMigration;43: };44:45: Bird::Bird(COLOR color, BOOL migrates):46: itsColor(color), itsMigration(migrates)47: {48: cout << "Bird constructor...\n";49: }50:51: class Pegasus : public Horse, public Bird52: {53: public:54: void Chirp()const { Whinny(); }55: Pegasus(COLOR, HANDS, BOOL,long);56: ~Pegasus() {cout << "Pegasus destructor...\n";}57: virtual long GetNumberBelievers() const 58: { 59: return itsNumberBelievers; 60: }61:62: private:63: long itsNumberBelievers;64: };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -