📄 ch13.htm
字号:
10: {
11: public:
12: Animal(int);
13: virtual ~Animal() { cout << "Animal destructor...\n"; }
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 << "Animal constructor...\n";
24: }
25:
26: class Horse : virtual public Animal
27: {
28: public:
29: Horse(COLOR color, HANDS height, int age);
30: virtual ~Horse() { cout << "Horse destructor...\n"; }
31: virtual void Whinny()const { cout << "Whinny!... "; }
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 << "Horse constructor...\n";
44: }
45:
46: class Bird : virtual public Animal
47: {
48: public:
49: Bird(COLOR color, BOOL migrates, int age);
50: virtual ~Bird() {cout << "Bird destructor...\n"; }
51: virtual void Chirp()const { cout << "Chirp... "; }
52: virtual void Fly()const
53: { cout << "I can fly! I can fly! I can fly! "; }
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 << "Bird constructor...\n";
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 << "Pegasus destructor...\n";}
74: virtual long GetNumberBelievers() const
75: { return itsNumberBelievers; }
76: virtual COLOR GetColor()const { return Horse::itsColor; }
77: private:
78: long itsNumberBelievers;
79: };
80:
81: Pegasus::Pegasus(
82: COLOR aColor,
83: HANDS height,
84: BOOL migrates,
85: long NumBelieve,
86: int age):
87: Horse(aColor, height,age),
88: Bird(aColor, migrates,age),
89: Animal(age*2),
90: itsNumberBelievers(NumBelieve)
91: {
92: cout << "Pegasus constructor...\n";
93: }
94:
95: int main()
96: {
97: Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10, 2);
98: int age = pPeg->GetAge();
99: cout << "This pegasus is " << age << " years old.\n";
100: delete pPeg;
101: return 0;
<TT>102: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Animal constructor...
Horse constructor...
Bird constructor...
Pegasus constructor...
This pegasus is 4 years old.
Pegasus destructor...
Bird destructor...
Horse destructor...
Animal destructor...
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis</B></FONT><B>: </B>On line 26, <TT>Horse</TT>
declares that it inherits virtually from <TT>Animal</TT>, and on line 46, <TT>Bird</TT>
makes the same declaration. Note that the constructors for both <TT>Bird</TT> and
<TT>Animal</TT> still initialize the <TT>Animal</TT> object.</P>
<P><TT>Pegasus</TT> inherits from both <TT>Bird</TT> and <TT>Animal</TT>, and as
the most derived object of <TT>Animal</TT>, it also initializes <TT>Animal</TT>.
It is <TT>Pegasus</TT>' initialization which is called, however, and the calls to
<TT>Animal</TT>'s constructor in <TT>Bird</TT> and <TT>Horse</TT> are ignored. You
can see this because the value <TT>2</TT> is passed in, and <TT>Horse</TT> and <TT>Bird</TT>
pass it along to <TT>Animal</TT>, but <TT>Pegasus</TT> doubles it. The result, 4,
is reflected in the printout on line 99 and as shown in the output.</P>
<P><TT>Pegasus</TT> no longer has to disambiguate the call to <TT>GetAge()</TT>,
and so is free to simply inherit this function from <TT>Animal</TT>. Note that <TT>Pegasus</TT>
must still disambiguate the call to <TT>GetColor()</TT>, as this function is in both
of its base classes and not in <TT>Animal</TT>.
<H3 ALIGN="CENTER"><A NAME="Heading29"></A><FONT COLOR="#000077">Declaring Classes
for Virtual Inheritance</FONT></H3>
<P>To ensure that derived classes have only one instance of common base classes,
declare the intermediate classes to inherit virtually from the base class. Example
1:</P>
<PRE><FONT COLOR="#0066FF">class Horse : virtual public Animal
class Bird : virtual public Animal
class Pegasus : public Horse, public Bird
</FONT></PRE>
<P>Example 2:</P>
<PRE><FONT COLOR="#0066FF">class Schnauzer : virtual public Dog
class Poodle : virtual public Dog
class Schnoodle : public Schnauzer, public Poodle
</FONT></PRE>
<H4 ALIGN="CENTER"><A NAME="Heading30"></A><FONT COLOR="#000077">Problems with Multiple
Inheritance</FONT></H4>
<P>Although multiple inheritance offers a number of advantages over single inheritance,
there are many C++ programmers who are reluctant to use it. The problems they cite
are that many compilers don't support it yet, that it makes debugging harder, and
that nearly everything that can be done with multiple inheritance can be done without
it.</P>
<P>These are valid concerns, and you will want to be on your guard against installing
needless complexity into your programs. Some debuggers have a hard time with multiple
inheritance, and some designs are needlessly made complex by using multiple inheritance
when it is not needed.
<BLOCKQUOTE>
<P>
<HR>
<B>DO</B> use multiple inheritance when a new class needs functions and features
from more than one base class<B>. DO</B> use virtual inheritance when the most derived
classes must have only one instance of the shared base class. DO initialize the shared
base class from the most derived class when using virtual base classes. <B>DON'T</B>
use multiple inheritance when single inheritance will do.
<HR>
</BLOCKQUOTE>
<H4 ALIGN="CENTER"><A NAME="Heading31"></A><FONT COLOR="#000077">Mixins and Capabilities
Classes</FONT></H4>
<P>One way to strike a middle ground between multiple inheritance and single inheritance
is to use what are called mixins. Thus, you might have your <TT>Horse</TT> class
derive from <TT>Animal</TT> and from <TT>Displayable</TT>. <TT>Displayable</TT> would
just add a few methods for displaying any object onscreen.</P>
<DL>
<DD>
<HR>
<FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B>A<I> mixin</I> , or <I>capability</I>
class, is a class that adds functionality without adding much or any data.
<HR>
</DL>
<P>Capability classes are mixed into a derived class like any other class might be,
by declaring the derived class to inherit publicly from them. The only difference
between a capability class and any other class is that the capability class has little
or no data. This is an arbitrary distinction, of course, and is just a shorthand
way of noting that at times all you want to do is mix in some additional capabilities
without complicating the derived class.</P>
<P>This will, for some debuggers, make it easier to work with mixins than with more
complex multiply inherited objects. There is also less likelihood of ambiguity in
accessing the data in the other principal base class.</P>
<P>For example, if <TT>Horse</TT> derives from <TT>Animal</TT> and from <TT>Displayable</TT>,
<TT>Displayable</TT> would have no data. <TT>Animal</TT> would be just as it always
was, so all the data in <TT>Horse</TT> would derive from <TT>Animal</TT>, but the
functions in <TT>Horse</TT> would derive from both.</P>
<P>The term mixin comes from an ice-cream store in Sommerville, Massachusetts, where
candies and cakes were mixed into the basic ice-cream flavors. This seemed like a
good metaphor to some of the object-oriented programmers who used to take a summer
break there, especially while working with the object-oriented programming language
SCOOPS.
<H3 ALIGN="CENTER"><A NAME="Heading32"></A><FONT COLOR="#000077">Abstract Data Types</FONT></H3>
<P>Often, you will create a hierarchy of classes together. For example, you might
create a <TT>Shape</TT> class, and derive from that <TT>Rectangle</TT> and <TT>Circle</TT>.
From <TT>Rectangle</TT>, you might derive <TT>Square</TT>, as a special case of <TT>Rectangle</TT>.</P>
<P>Each of the derived classes will override the <TT>Draw()</TT> method, the <TT>GetArea()</TT>
method, and so forth. Listing 13.7 illustrates a bare-bones implementation of the
<TT>Shape</TT> class and its derived <TT>Circle</TT> and <TT>Rectangle</TT> classes.</P>
<P><A NAME="Heading33"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.7. Shape
classes.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1: //Listing 13.7. Shape classes.
2:
3: #include <iostream.h>
4:
5: enum BOOL { FALSE, TRUE };
6:
7: class Shape
8: {
9: public:
10: Shape(){}
11: ~Shape(){}
12: virtual long GetArea() { return -1; } // error
13: virtual long GetPerim() { return -1; }
14: virtual void Draw() {}
15: private:
16: };
17:
18: class Circle : public Shape
19: {
20: public:
21: Circle(int radius):itsRadius(radius){}
22: ~Circle(){}
23: long GetArea() { return 3 * itsRadius * itsRadius; }
24: long GetPerim() { return 9 * itsRadius; }
25: void Draw();
26: private:
27: int itsRadius;
28: int itsCircumference;
29: };
30:
31: void Circle::Draw()
32: {
33: cout << "Circle drawing routine here!\n";
34: }
35:
36:
37: class Rectangle : public Shape
38: {
39: public:
40: Rectangle(int len, int width):
41: itsLength(len), itsWidth(width){}
42: ~Rectangle(){}
43: virtual long GetArea() { return itsLength * itsWidth; }
44: virtual long GetPerim() {return 2*itsLength + 2*itsWidth; }
45: virtual int GetLength() { return itsLength; }
46: virtual int GetWidth() { return itsWidth; }
47: virtual void Draw();
48: private:
49: int itsWidth;
50: int itsLength;
51: };
52:
53: void Rectangle::Draw()
54: {
55: for (int i = 0; i<itsLength; i++)
56: {
57: for (int j = 0; j<itsWidth; j++)
58: cout << "x ";
59:
60: cout << "\n";
61: }
62: }
63:
64: class Square : public Rectangle
65: {
66: public:
67: Square(int len);
68: Square(int len, int width);
69: ~Square(){}
70: long GetPerim() {return 4 * GetLength();}
71: };
72:
73: Square::Square(int len):
74: Rectangle(len,len)
75: {}
76:
77: Square::Square(int len, int width):
78: Rectangle(len,width)
79:
80: {
81: if (GetLength() != GetWidth())
82: cout << "Error, not a square... a Rectangle??\n";
83: }
84:
85: int main()
86: {
87: int choice;
88: BOOL fQuit = FALSE;
89: Shape * sp;
90:
91: while (1)
92: {
93: cout << "(1)Circle (2)Rectangle (3)Square (0)Quit: ";
94: cin >> choice;
95:
96: switch (choice)
97: {
98: case 1: sp = new Circle(5);
99: break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -