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

📄 ch13.htm

📁 一本好的VC学习书,本人就是使用这本书开始学习的vc,希望能对大家有帮助
💻 HTM
📖 第 1 页 / 共 5 页
字号:
x x x x xx x x x xx x x x xx x x x x(1)Circle (2)Rectangle (3)Square (0)Quit:0</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis</B></FONT><B>: </B>On lines 7-16, the <TT>Shape</TT>class is declared. The <TT>GetArea()</TT> and <TT>GetPerim()</TT> methods returnan error value, and <TT>Draw()</TT> takes no action. After all, what does it meanto draw a Shape? Only types of shapes (circles, rectangle, and so on) can be drawn,<TT>Shapes</TT> as an abstraction cannot be drawn.</P><P><TT>Circle</TT> derives from <TT>Shape</TT> and overrides the three virtual methods.Note that there is no reason to add the word &quot;virtual,&quot; as that is partof their inheritance. But there is no harm in doing so either, as shown in the <TT>Rectangle</TT>class on lines 43, 44, and 47. It is a good idea to include the term virtual as areminder, a form of documentation.</P><P><TT>Square</TT> derives from <TT>Rectangle</TT>, and it too overrides the <TT>GetPerim()</TT>method, inheriting the rest of the methods defined in <TT>Rectangle</TT>.</P><P>It is troubling, though, that a client might try to instantiate a <TT>Shape</TT>object, and it might be desirable to make that impossible. The <TT>Shape</TT> classexists only to provide an interface for the classes derived from it; as such it isan Abstract Data Type, or ADT.</P><DL>	<DD><HR><FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B>An <I>Abstract Data Type </I>represents	a concept (like shape) rather than an object (like circle). In C++, an ADT is always	the base class to other classes, and it is not valid to make an instance of an ADT.	<HR></DL><H4 ALIGN="CENTER"><A NAME="Heading35"></A><FONT COLOR="#000077">Pure Virtual Functions</FONT></H4><P>C++ supports the creation of abstract data types with pure virtual functions.A virtual function ismade pure by initializing it with zero, as in</P><PRE><FONT COLOR="#0066FF">virtual void Draw() = 0;</FONT></PRE><P>Any class with one or more pure virtual functions is an ADT, and it is illegalto instantiate an object of a class that is an ADT. Trying to do so will cause acompile-time error. Putting a pure virtual function in your class signals two thingsto clients of your class:<UL>	<LI>Don't make an object of this class, derive from it.	<P>	<LI>Make sure you override the pure virtual function.</UL><P>Any class that derives from an ADT inherits the pure virtual function as pure,and so must override every pure virtual function if it wants to instantiate objects.Thus, if <TT>Rectangle</TT> inherits from <TT>Shape</TT>, and <TT>Shape</TT> hasthree pure virtual functions, <TT>Rectangle</TT> must override all three or it toowill be an ADT. Listing 13.8 rewrites the <TT>Shape</TT> class to be an abstractdata type. To save space, the rest of Listing 13.7 is not reproduced here. Replacethe declaration of <TT>Shape</TT> in Listing 13.7, lines 7-16, with the declarationof <TT>Shape</TT> in Listing 13.8 and run the program again.</P><P><A NAME="Heading36"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.8. AbstractData Types.</B></FONT></P><PRE><FONT COLOR="#0066FF">1:  class Shape2:  {3:  public:4:       Shape(){}5:       ~Shape(){}6:       virtual long GetArea() = 0; // error7:       virtual long GetPerim()= 0;8:       virtual void Draw() = 0;9:  private:</FONT></PRE><P><TT>10: };</TT></P><PRE><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 xx x x x xx x x x xx x x x xx x x x x(1)Circle (2)Rectangle (3)Square (0)Quit: 0</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>As you can see, the workingsof the program are totally unaffected. The only difference is that it would now beimpossible to make an object of class <TT>Shape</TT>.<H3 ALIGN="CENTER"><A NAME="Heading38"></A><FONT COLOR="#000077">Abstract Data Types</FONT></H3><P>Declare a class to be an abstract data type by including one or more pure virtualfunctions in the class declaration. Declare a pure virtual function by writing <TT>=0</TT> after the function declaration. Example:</P><PRE><FONT COLOR="#0066FF">class Shape{virtual void Draw() = 0;    // pure virtual};</FONT></PRE><H4 ALIGN="CENTER"><A NAME="Heading39"></A><FONT COLOR="#000077">Implementing PureVirtual Functions</FONT></H4><P>Typically, the pure virtual functions in an abstract base class are never implemented.Because no objects of that type are ever created, there is no reason to provide implementations,and the ADT works purely as the definition of an interface to objects which derivefrom it.</P><P>It is possible, however, to provide an implementation to a pure virtual function.The function can then be called by objects derived from the ADT, perhaps to providecommon functionality to all the overridden functions. Listing 13.9 reproduces Listing13.7, this time with <TT>Shape</TT> as an ADT and with an implementation for thepure virtual function <TT>Draw()</TT>. The <TT>Circle</TT> class overrides <TT>Draw()</TT>,as it must, but it then chains up to the base class function for additional functionality.</P><P>In this example, the additional functionality is simply an additional messageprinted, but one can imagine that the base class provides a shared drawing mechanism,perhaps setting up a window that all derived classes will use.</P><P><A NAME="Heading40"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.9. Implementingpure virtual functions.</B></FONT></P><PRE><FONT COLOR="#0066FF">1:     //Implementing pure virtual functions2:3:     #include &lt;iostream.h&gt;4:5:     enum BOOL { FALSE, TRUE };6:7:     class Shape8:     {9:     public:10:       Shape(){}11:       ~Shape(){}12:       virtual long GetArea() = 0; // error13:       virtual long GetPerim()= 0;14:       virtual void Draw() = 0;15:    private:16:    };17:18:     void Shape::Draw()19:    {20:       cout &lt;&lt; &quot;Abstract drawing mechanism!\n&quot;;21:    }22:23:    class Circle : public Shape24:    {25:    public:26:          Circle(int radius):itsRadius(radius){}27:          ~Circle(){}28:          long GetArea() { return 3 * itsRadius * itsRadius; }29:          long GetPerim() { return 9 * itsRadius; }30:          void Draw();31:    private:32:       int itsRadius;33:       int itsCircumference;34:    };35:36:    void Circle::Draw()37:    {38:       cout &lt;&lt; &quot;Circle drawing routine here!\n&quot;;39:       Shape::Draw();40:    }41:42: 43:    class Rectangle : public Shape44:    {45:    public:46:          Rectangle(int len, int width):47:             itsLength(len), itsWidth(width){}48:          ~Rectangle(){}49:          long GetArea() { return itsLength * itsWidth; }50:          long GetPerim() {return 2*itsLength + 2*itsWidth; }51:          virtual int GetLength() { return itsLength; }52:          virtual int GetWidth() { return itsWidth; }53:          void Draw();54:    private:55:       int itsWidth;56:       int itsLength;57:    };58:59:    void Rectangle::Draw()60:    {61:       for (int i = 0; i&lt;itsLength; i++)62:       {63:          for (int j = 0; j&lt;itsWidth; j++)64:             cout &lt;&lt; &quot;x &quot;;65:66:          cout &lt;&lt; &quot;\n&quot;;67:       }68:       Shape::Draw();69:    }70:71:72:    class Square : public Rectangle73:    {74:    public:75:          Square(int len);76:          Square(int len, int width);77:          ~Square(){}78:          long GetPerim() {return 4 * GetLength();}79:    };80: 81:    Square::Square(int len):82:       Rectangle(len,len)83:    {}84:85:    Square::Square(int len, int width):86:       Rectangle(len,width)87:88:    {89:       if (GetLength() != GetWidth())90:          cout &lt;&lt; &quot;Error, not a square... a Rectangle??\n&quot;;91:    }92:93:    int main()94:    {95:       int choice;96:       BOOL fQuit = FALSE;97:       Shape * sp;98: 99:       while (1)100:      {101:         cout &lt;&lt; &quot;(1)Circle (2)Rectangle (3)Square (0)Quit: &quot;;102:         cin &gt;&gt; choice;103:104:         switch (choice)105:         {106:            case 1: sp = new Circle(5);107:            break;108:            case 2: sp = new Rectangle(4,6);109:            break;110:            case 3: sp = new Square (5);111:            break;112:            default: fQuit = TRUE;113:            break;114:         }115:         if (fQuit)116:            break;117:118:         sp-&gt;Draw();119:         cout &lt;&lt; &quot;\n&quot;;120:      }121:     return 0;<TT>122: }</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 xAbstract drawing mechanism!(1)Circle (2)Rectangle (3)Square (0)Quit: 3x x x x xx x x x xx x x x xx x x x xx x x x xAbstract drawing mechanism!(1)Circle (2)Rectangle (3)Square (0)Quit: 0</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis</B></FONT><B>: </B>On lines 7-16, the abstractdata type <TT>Shape</TT> is declared, with all three of its accessor methods declaredto be pure virtual. Note that this is not necessary. If any one were declared purevirtual, the class would have been an ADT.</P><P>The <TT>GetArea()</TT> and <TT>GetPerim()</TT> methods are not implemented, but<TT>Draw()</TT> is. <TT>Circle</TT> and <TT>Rectangle</TT> both override <TT>Draw()</TT>,and both chain up to the base method, taking advantage of shared functionality inthe base class.<H4 ALIGN="CENTER"><A NAME="Heading42"></A><FONT COLOR="#000077">Complex Hierarchiesof Abstraction</FONT></H4><P>At times, you will derive ADTs from other ADTs. It may be that you will want tomake some of the derived pure virtual functions non-pure, and leave others pure.</P><P>If you create the <TT>Animal</TT> class, you may make <TT>Eat()</TT>,<TT> Sleep()</TT>,<TT>Move()</TT>, and <TT>Reproduce()</TT> all be pure virtual functions. Perhaps from<TT>Animal</TT> you derive <TT>Mammal</TT> and <TT>Fish</TT>.</P><P>On examination, you decide that every <TT>Mammal</TT> will reproduce in the sameway, and so you make <TT>Mammal::Reproduce()</TT> be non-pure, but you leave <TT>Eat()</TT>,<TT>Sleep()</TT>, and <TT>Move()</TT> as pure virtual functions.</P><P>From <TT>Mammal</TT> you derive <TT>Dog</TT>, and <TT>Dog</TT> must override andimplement the three remaining pure virtual functions so that you can make objectsof type <TT>Dog</TT>.</P><P>What you've said, as class designer, is that no <TT>Animal</TT>s or <TT>Mammal</TT>scan be instantiated, but that all <TT>Mammal</TT>s may inherit the provided <TT>Reproduce()</TT>method without overriding it.</P><P>Listing 13.10 illustrates this technique with a bare-bones implementation of theseclasses.</P><P><A NAME="Heading43"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 13.10. DerivingADTs from other ADTs.</B></FONT></P><PRE><FONT COLOR="#0066FF">1:     // Listing 13.102:     // Deriving ADTs from other ADTs3:     #include &lt;iostream.h&gt;4:5:     enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;6:     enum BOOL { FALSE, TRUE };7:8:     class Animal        // common base to both horse and bird9:     {10:    public:11:       Animal(int);12:       virtual ~Animal() { cout &lt;&lt; &quot;Animal destructor...\n&quot;; }13:       virtual int GetAge() const { return itsAge; }14:       virtual void SetAge(int age) { itsAge = age; }15:       virtual void Sleep() const = 0;16:       virtual void Eat() const = 0;17:       virtual void Reproduce() const = 0;18:       virtual void Move() const = 0;19:       virtual void Speak()

⌨️ 快捷键说明

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