📄 ch13.htm
字号:
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 Animal47: {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 Bird69: {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 asthe 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. Youcan 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 bothof its base classes and not in <TT>Animal</TT>.<H3 ALIGN="CENTER"><A NAME="Heading29"></A><FONT COLOR="#000077">Declaring Classesfor 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. Example1:</P><PRE><FONT COLOR="#0066FF">class Horse : virtual public Animalclass Bird : virtual public Animalclass Pegasus : public Horse, public Bird</FONT></PRE><P>Example 2:</P><PRE><FONT COLOR="#0066FF">class Schnauzer : virtual public Dogclass Poodle : virtual public Dogclass Schnoodle : public Schnauzer, public Poodle</FONT></PRE><H4 ALIGN="CENTER"><A NAME="Heading30"></A><FONT COLOR="#000077">Problems with MultipleInheritance</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 citeare that many compilers don't support it yet, that it makes debugging harder, andthat nearly everything that can be done with multiple inheritance can be done withoutit.</P><P>These are valid concerns, and you will want to be on your guard against installingneedless complexity into your programs. Some debuggers have a hard time with multipleinheritance, and some designs are needlessly made complex by using multiple inheritancewhen 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 CapabilitiesClasses</FONT></H4><P>One way to strike a middle ground between multiple inheritance and single inheritanceis to use what are called mixins. Thus, you might have your <TT>Horse</TT> classderive from <TT>Animal</TT> and from <TT>Displayable</TT>. <TT>Displayable</TT> wouldjust 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 differencebetween a capability class and any other class is that the capability class has littleor no data. This is an arbitrary distinction, of course, and is just a shorthandway of noting that at times all you want to do is mix in some additional capabilitieswithout complicating the derived class.</P><P>This will, for some debuggers, make it easier to work with mixins than with morecomplex multiply inherited objects. There is also less likelihood of ambiguity inaccessing 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 alwayswas, so all the data in <TT>Horse</TT> would derive from <TT>Animal</TT>, but thefunctions in <TT>Horse</TT> would derive from both.</P><P>The term mixin comes from an ice-cream store in Sommerville, Massachusetts, wherecandies and cakes were mixed into the basic ice-cream flavors. This seemed like agood metaphor to some of the object-oriented programmers who used to take a summerbreak there, especially while working with the object-oriented programming languageSCOOPS.<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 mightcreate 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. Shapeclasses.</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 Shape8: {9: public:10: Shape(){}11: ~Shape(){}12: virtual long GetArea() { return -1; } // error13: virtual long GetPerim() { return -1; }14: virtual void Draw() {}15: private:16: };17:18: class Circle : public Shape19: {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 Shape38: {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 Rectangle65: {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;100: case 2: sp = new Rectangle(4,6);101: break;102: case 3: sp = new Square(5);103: break;104: default: fQuit = TRUE;105: break;106: }107: if (fQuit)108: break;109:110: sp->Draw();111: cout << "\n";112: }113: return 0;<TT>114: }</TT></FONT><FONT COLOR="#0066FF">Output: (1)Circle (2)Rectangle (3)Square (0)Quit: 2x x x x x xx x x x x xx x x x x xx x x x x x(1)Circle (2)Rectangle (3)Square (0)Quit:3x x x x x
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -