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

📄 ch13.htm

📁 一本好的VC学习书,本人就是使用这本书开始学习的vc,希望能对大家有帮助
💻 HTM
📖 第 1 页 / 共 5 页
字号:
65: 66:    Pegasus::Pegasus(67:        COLOR aColor, 68:        HANDS height, 69:        BOOL migrates, 70:        long NumBelieve):71:    Horse(aColor, height),72:    Bird(aColor, migrates),73:    itsNumberBelievers(NumBelieve)74:    {75:       cout &lt;&lt; &quot;Pegasus constructor...\n&quot;;76:    }77:78:    int main()79:    {80:       Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10);81:       pPeg-&gt;Fly();82:       pPeg-&gt;Whinny();83:       cout &lt;&lt; &quot;\nYour Pegasus is &quot; &lt;&lt; pPeg-&gt;GetHeight();84:       cout &lt;&lt; &quot; hands tall and &quot;;85:       if (pPeg-&gt;GetMigration())86:          cout &lt;&lt; &quot;it does migrate.&quot;;87:       else88:          cout &lt;&lt; &quot;it does not migrate.&quot;;89:       cout &lt;&lt; &quot;\nA total of &quot; &lt;&lt; pPeg-&gt;GetNumberBelievers();90:       cout &lt;&lt; &quot; people believe it exists.\n&quot;;91:       delete pPeg;92:     return 0;<TT>93: }</TT></FONT><FONT COLOR="#0066FF">Output: Horse constructor...Bird constructor...Pegasus constructor...I can fly! I can fly! I can fly! Whinny!...Your Pegasus is 5 hands tall and it does migrate.A total of 10 people believe it exists.Pegasus destructor...Bird destructor...Horse destructor... </FONT></PRE><P><FONT COLOR="#0000AA"><B>Analysis: </B></FONT>On lines 8-19, the <TT>Horse</TT>class is declared. The constructor takes two parameters, both using enumerationsdeclared on lines 5 and 6. The implementation of the constructor on lines 21-25 simplyinitializes the member variables and prints a message.</P><P>On lines 27-43, the <TT>Bird</TT> class is declared, and the implementation ofits constructor is on lines 45-49. Again, the <TT>Bird</TT> class takes two parameters.Interestingly, the <TT>Horse</TT> constructor takes color (so that you can detecthorses of different colors), and the <TT>Bird</TT> constructor takes the color ofthe feathers (so those of one feather can stick together). This leads to a problemwhen you want to ask the <TT>Pegasus</TT> for its color, which you'll see in thenext example.</P><P>The <TT>Pegasus</TT> class itself is declared on lines 51-64, and its constructoris on lines 66-72. The initialization of the <TT>Pegasus</TT> object includes threestatements. First, the <TT>Horse</TT> constructor is initialized with color and height.Then the <TT>Bird</TT> constructor is initialized with color and the Boolean. Finally,the <TT>Pegasus</TT> member variable <TT>itsNumberBelievers</TT> is initialized.Once all that is accomplished, the body of the <TT>Pegasus</TT> constructor is called.</P><P>In the <TT>main()</TT> function, a <TT>Pegasus</TT> pointer is created and usedto access the member functions of the base objects.<H4 ALIGN="CENTER"><A NAME="Heading20"></A><FONT COLOR="#000077">Ambiguity Resolution</FONT></H4><P>In Listing 13.4, both the <TT>Horse</TT> class and the <TT>Bird</TT> class havea method <TT>GetColor()</TT>. You may need to ask the <TT>Pegasus</TT> object toreturn its color, but you have a problem: the <TT>Pegasus</TT> class inherits fromboth <TT>Bird</TT> and <TT>Horse</TT>. They both have a color, and their methodsfor getting that color have the same names and signature. This creates an ambiguityfor the compiler, which you must resolve.</P><P>If you simply write</P><PRE><FONT COLOR="#0066FF">COLOR currentColor = pPeg-&gt;GetColor();</FONT></PRE><P>you will get a compiler error:</P><PRE><FONT COLOR="#0066FF">Member is ambiguous: `Horse::GetColor' and `Bird::GetColor'</FONT></PRE><P>You can resolve the ambiguity with an explicit call to the function you wish toinvoke:</P><PRE><FONT COLOR="#0066FF">COLOR currentColor = pPeg-&gt;Horse::GetColor();</FONT></PRE><P>Anytime you need to resolve which class a member function or member data inheritsfrom, you can fully qualify the call by prepending the class name to the base classdata or function.</P><P>Note that if <TT>Pegasus</TT> were to override this function, the problem wouldbe moved, as it should be, into the <TT>Pegasus</TT> member function:</P><PRE><FONT COLOR="#0066FF">virtual COLOR GetColor()const { return Horse::itsColor; }</FONT></PRE><P>This hides the problem from clients of the <TT>Pegasus</TT> class, and encapsulateswithin <TT>Pegasus</TT> the knowledge of which base class it wishes to inherit itscolor from. A client is still free to force the issue by writing:</P><PRE><FONT COLOR="#0066FF">COLOR currentColor = pPeg-&gt;Bird::GetColor();</FONT></PRE><H4 ALIGN="CENTER"><A NAME="Heading21"></A><FONT COLOR="#000077">Inheriting fromShared Base Class</FONT></H4><P>What happens if both <TT>Bird</TT> and <TT>Horse</TT> inherit from a common baseclass, such as <TT>Animal</TT>? Figure 13.2 illustrates what this looks like.</P><P>As you can see in Figure 13.2, two base class objects exist. When a function ordata member is called in the shared base class, another ambiguity exists. For example,if <TT>Animal</TT> declares <TT>itsAge</TT> as a member variable and <TT>GetAge()</TT>as a member function, and you call <TT>pPeg-&gt;GetAge()</TT>, did you mean to callthe <TT>GetAge()</TT> function you inherit from <TT>Animal</TT> by way of <TT>Horse</TT>,or by way of <TT>Bird</TT>? You must resolve this ambiguity as well, as illustratedin Listing 13.5.<BR><BR><A NAME="Heading22"></A><A HREF="13zcp02.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch13/13zcp02.jpg"><FONT COLOR="#000077">Figure13.2.</FONT></A><FONT COLOR="#000077"> </FONT><I>Common base classes.</I></P><P><A NAME="Heading23"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.5. Commonbase classes.</B></FONT></P><PRE><FONT COLOR="#0066FF">1:     // Listing 13.52:     // Common base classes3:     #include &lt;iostream.h&gt;4:5:     typedef int HANDS;6:     enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;7:     enum BOOL { FALSE, TRUE };8:9:     class Animal        // common base to both horse and bird10:    {11:    public:12:       Animal(int);13:       virtual ~Animal() { cout &lt;&lt; &quot;Animal destructor...\n&quot;; }14:       virtual int GetAge() const { return itsAge; }15:       virtual void SetAge(int age) { itsAge = age; }16:    private:17:       int itsAge;18:    };19:20:    Animal::Animal(int age):21:    itsAge(age)22:    {23:       cout &lt;&lt; &quot;Animal constructor...\n&quot;;24:    }25:26:    class Horse : public Animal27:    {28:    public:29:       Horse(COLOR color, HANDS height, int age);30:       virtual ~Horse() { cout &lt;&lt; &quot;Horse destructor...\n&quot;; }31:       virtual void Whinny()const { cout &lt;&lt; &quot;Whinny!... &quot;; }32:       virtual HANDS GetHeight() const { return itsHeight; }33:       virtual COLOR GetColor() const { return itsColor; }34:    protected:35:       HANDS itsHeight;36:       COLOR itsColor;37:    };38: 39:    Horse::Horse(COLOR color, HANDS height, int age):40:       Animal(age),41:       itsColor(color),itsHeight(height)42:    {43:       cout &lt;&lt; &quot;Horse constructor...\n&quot;;44:    }45:46:    class Bird : public Animal47:    {48:    public:49:       Bird(COLOR color, BOOL migrates, int age);50:       virtual ~Bird() {cout &lt;&lt; &quot;Bird destructor...\n&quot;;  }51:       virtual void Chirp()const { cout &lt;&lt; &quot;Chirp... &quot;;  }52:       virtual void Fly()const 53:           { cout &lt;&lt; &quot;I can fly! I can fly! I can fly! &quot;; }54:       virtual COLOR GetColor()const { return itsColor; }55:       virtual BOOL GetMigration() const { return itsMigration; }56:    protected:57:       COLOR itsColor;58:       BOOL itsMigration;59:    };60:61:    Bird::Bird(COLOR color, BOOL migrates, int age):62:       Animal(age),63:       itsColor(color), itsMigration(migrates)64:    {65:       cout &lt;&lt; &quot;Bird constructor...\n&quot;;66:    }67:68:    class Pegasus : public Horse, public Bird69:    {70:    public:71:       void Chirp()const { Whinny(); }72:       Pegasus(COLOR, HANDS, BOOL, long, int);73:       ~Pegasus() {cout &lt;&lt; &quot;Pegasus destructor...\n&quot;;}74:       virtual long GetNumberBelievers() const 75:          { return  itsNumberBelievers; }76:       virtual COLOR GetColor()const { return Horse::itsColor; }77:       virtual int GetAge() const { return Horse::GetAge(); }78:    private:79:       long itsNumberBelievers;80:    };81: 82:    Pegasus::Pegasus(83:       COLOR aColor,84:       HANDS height,85:       BOOL migrates,86:       long NumBelieve,87:       int age):88:    Horse(aColor, height,age),89:    Bird(aColor, migrates,age),90:    itsNumberBelievers(NumBelieve)91:    {92:       cout &lt;&lt; &quot;Pegasus constructor...\n&quot;;93:    }94:95:    int main()96:    {97:       Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10, 2);98:       int age = pPeg-&gt;GetAge();99:       cout &lt;&lt; &quot;This pegasus is &quot; &lt;&lt; age &lt;&lt; &quot; years old.\n&quot;;100:      delete pPeg;101:     return 0;<TT>102: }</TT></FONT><FONT COLOR="#0066FF">Output: Animal constructor...Horse constructor...Animal constructor...Bird constructor...Pegasus constructor...This pegasus is 2 years old.Pegasus destructor...Bird destructor...Animal destructor...Horse destructor...Animal destructor... </FONT></PRE><P><FONT COLOR="#0000AA"><B>Analysis:</B></FONT><B> </B>There are a number of interestingfeatures to this listing. The <TT>Animal</TT> class is declared on lines 9-18. <TT>Animal</TT>adds one member variable, <TT>itsAge</TT> and an accessor, <TT>SetAge()</TT>.</P><P>On line 26, the <TT>Horse</TT> class is declared to derive from <TT>Animal</TT>.The <TT>Horse</TT> constructor now has a third parameter, <TT>age</TT>, which itpasses to its base class, <TT>Animal</TT>. Note that the <TT>Horse</TT> class doesnot override <TT>GetAge()</TT>, it simply inherits it.</P><P>On line 46, the <TT>Bird</TT> class is declared to derive from <TT>Animal</TT>.Its constructor also takes an age and uses it to initialize its base class, <TT>Animal</TT>.It also inherits <TT>GetAge()</TT> without overriding it.</P><P><TT>Pegasus</TT> inherits from both <TT>Bird</TT> and from <TT>Animal</TT>, andso has two <TT>Animal</TT> classes in its inheritance chain. If you were to call<TT>GetAge()</TT> on a <TT>Pegasus</TT> object, you would have to disambiguate, orfully qualify, the method you want if <TT>Pegasus</TT> did not override the method.</P><P>This is solved on line 76 when the <TT>Pegasus</TT> object overrides <TT>GetAge()</TT>to do nothing more than to chain up--that is, to call the same method in a base class.</P><P>Chaining up is done for two reasons: either to disambiguate which base class tocall, as in this case, or to do some work and then let the function in the base classdo some more work. At times, you may want to do work and then chain up, or chainup and then do the work when the base class function returns.</P><P>The <TT>Pegasus</TT> constructor takes five parameters: the creature's color,its height (in <TT>HANDS</TT>), whether or not it migrates, how many believe in it,and its age. The constructor initializes the <TT>Horse</TT> part of the <TT>Pegasus</TT>with the color, height, and age on line 88. It initializes the <TT>Bird</TT> partwith color, whether it migrates, and age on line 89. Finally, it initializes <TT>itsNumberBelievers</TT>on line 90.</P><P>The call to the <TT>Horse</TT> constructor on line 88 invokes the implementationshown on line 39. The <TT>Horse</TT> constructor uses the <TT>age</TT> parameterto initialize the <TT>Animal</TT> part of the <TT>Horse</TT> part of the <TT>Pegasus</TT>.It then goes on to initialize the two member variables of <TT>Horse</TT>--<TT>itsColor</TT>and <TT>itsAge</TT>.</P><P>The call to the <TT>Bird</TT> constructor on line 89 invokes the implementationshown on line 46. Here too, the <TT>age</TT> parameter is used to initialize the<TT>Animal</TT> part of the <TT>Bird</TT>.</P><P>Note that the <TT>color</TT> parameter to the <TT>Pegasus</TT> is used to initializemember variables in each of <TT>Bird</TT> and <TT>Horse</TT>. Note also that the<TT>age</TT> is used to initialize <TT>itsAge</TT> in the <TT>Horse</TT>'s base <TT>Animal</TT>and in the <TT>Bird</TT>'s base <TT>Animal</TT>.<H4 ALIGN="CENTER"><A NAME="Heading25"></A><FONT COLOR="#000077">Virtual Inheritance</FONT></H4><P>In Listing 13.5, the <TT>Pegasus</TT> class went to some lengths to disambiguatewhich of its <TT>Animal</TT> base classes it meant to invoke. Most of the time, thedecision as to which one to use is arbitrary--after all, the <TT>Horse</TT> and the<TT>Bird</TT> have exactly the same base class.</P><P>It is possible to tell C++ that you do not want two copies of the shared baseclass, as shown in Figure 13.2, but rather to have a single shared base class, asshown in Figure 13.3.</P><P>You accomplish this by making <TT>Animal</TT> a virtual base class of both <TT>Horse</TT>and <TT>Bird</TT>. The <TT>Animal</TT> class does not change at all. The <TT>Horse</TT>and <TT>Bird</TT> classes change only in their use of the term virtual in their declarations.<TT>Pegasus</TT>, however, changes substantially.</P><P>Normally, a class's constructor initializes only its own variables and its baseclass. Virtually inherited base classes are an exception, however. They are initializedby their most derived class. Thus, <TT>Animal</TT> is initialized not by <TT>Horse</TT>and <TT>Bird</TT>, but by <TT>Pegasus</TT>. <TT>Horse</TT> and <TT>Bird</TT> haveto initialize <TT>Animal</TT> in their constructors, but these initializations willbe ignored when a <TT>Pegasus</TT> object is created.</P><P>Listing 13.6 rewrites Listing 13.5 to take advantage of virtual derivation.<BR><BR><A NAME="Heading26"></A><A HREF="13zcp03.gif" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch13/13zcp03.gif"><FONT COLOR="#000077">Figure13.3.</FONT></A><FONT COLOR="#000077"> </FONT><I>A diamond inheritance.</I></P><P><A NAME="Heading27"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.6. Illustrationof the use of virtual inheritance.</B></FONT></P><PRE><FONT COLOR="#0066FF">1:     // Listing 13.62:     // Virtual inheritance3:     #include &lt;iostream.h&gt;4:5:     typedef int HANDS;6:     enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;7:     enum BOOL { FALSE, TRUE };8:9:     class Animal        // common base to both horse and bird10:    {11:    public:12:       Animal(int);13:       virtual ~Animal() { cout &lt;&lt; &quot;Animal destructor...\n&quot;; }14:       virtual int GetAge() const { return itsAge; }15:       virtual void SetAge(int age) { itsAge = age; }16:    private:17:       int itsAge;18:    };19:20:    Animal::Animal(int age):21:    itsAge(age)22:    {23:       cout &lt;&lt; &quot;Animal constructor...\n&quot;;24:    }25:26:    class Horse : virtual public Animal27:    {

⌨️ 快捷键说明

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