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

📄 ch13.htm

📁 vc的电子书
💻 HTM
📖 第 1 页 / 共 5 页
字号:
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:    };
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 << "Pegasus constructor...\n";
76:    }
77:
78:    int main()
79:    {
80:       Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10);
81:       pPeg->Fly();
82:       pPeg->Whinny();
83:       cout << "\nYour Pegasus is " << pPeg->GetHeight();
84:       cout << " hands tall and ";
85:       if (pPeg->GetMigration())
86:          cout << "it does migrate.";
87:       else
88:          cout << "it does not migrate.";
89:       cout << "\nA total of " << pPeg->GetNumberBelievers();
90:       cout << " people believe it exists.\n";
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 enumerations
declared on lines 5 and 6. The implementation of the constructor on lines 21-25 simply
initializes the member variables and prints a message.</P>
<P>On lines 27-43, the <TT>Bird</TT> class is declared, and the implementation of
its 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 detect
horses of different colors), and the <TT>Bird</TT> constructor takes the color of
the feathers (so those of one feather can stick together). This leads to a problem
when you want to ask the <TT>Pegasus</TT> for its color, which you'll see in the
next example.</P>
<P>The <TT>Pegasus</TT> class itself is declared on lines 51-64, and its constructor
is on lines 66-72. The initialization of the <TT>Pegasus</TT> object includes three
statements. 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 used
to 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 have
a method <TT>GetColor()</TT>. You may need to ask the <TT>Pegasus</TT> object to
return its color, but you have a problem: the <TT>Pegasus</TT> class inherits from
both <TT>Bird</TT> and <TT>Horse</TT>. They both have a color, and their methods
for getting that color have the same names and signature. This creates an ambiguity
for 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 to
invoke:</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 inherits
from, you can fully qualify the call by prepending the class name to the base class
data or function.</P>
<P>Note that if <TT>Pegasus</TT> were to override this function, the problem would
be 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 encapsulates
within <TT>Pegasus</TT> the knowledge of which base class it wishes to inherit its
color 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 from
Shared Base Class</FONT></H4>
<P>What happens if both <TT>Bird</TT> and <TT>Horse</TT> inherit from a common base
class, 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 or
data 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 call
the <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 illustrated
in 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">Figure
13.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. Common
base classes.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1:     // Listing 13.5
2:     // Common base classes
3:     #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 bird
10:    {
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 Animal
27:    {
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 Animal
47:    {
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 Bird
69:    {
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 interesting
features 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 it
passes to its base class, <TT>Animal</TT>. Note that the <TT>Horse</TT> class does
not 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>, and
so 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, or
fully 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 to
call, as in this case, or to do some work and then let the function in the base class
do some more work. At times, you may want to do work and then chain up, or chain
up 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> part
with 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 implementation
shown on line 39. The <TT>Horse</TT> constructor uses the <TT>age</TT> parameter
to 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 implementation
shown 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 initialize
member 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 disambiguate
which of its <TT>Animal</TT> base classes it meant to invoke. Most of the time, the
decision 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 base
class, as shown in Figure 13.2, but rather to have a single shared base class, as
shown 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 base
class. Virtually inherited base classes are an exception, however. They are initialized
by 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> have
to initialize <TT>Animal</TT> in their constructors, but these initializations will
be 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">Figure
13.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. Illustration
of the use of virtual inheritance.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1:     // Listing 13.6
2:     // Virtual inheritance
3:     #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 bird

⌨️ 快捷键说明

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