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

📄 ch13.htm

📁 vc的电子书
💻 HTM
📖 第 1 页 / 共 5 页
字号:
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: 2
x x x x x x
x x x x x x
x x x x x x
x x x x x x

(1)Circle (2)Rectangle (3)Square (0)Quit:3
x x x x x
x x x x x
x x x x x
x x x x x
x 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 return
an error value, and <TT>Draw()</TT> takes no action. After all, what does it mean
to 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 part
of 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 a
reminder, 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> class
exists only to provide an interface for the classes derived from it; as such it is
an 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 illegal
to instantiate an object of a class that is an ADT. Trying to do so will cause a
compile-time error. Putting a pure virtual function in your class signals two things
to 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> has
three pure virtual functions, <TT>Rectangle</TT> must override all three or it too
will be an ADT. Listing 13.8 rewrites the <TT>Shape</TT> class to be an abstract
data type. To save space, the rest of Listing 13.7 is not reproduced here. Replace
the declaration of <TT>Shape</TT> in Listing 13.7, lines 7-16, with the declaration
of <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. Abstract
Data Types.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1:  class Shape
2:  {
3:  public:
4:       Shape(){}
5:       ~Shape(){}
6:       virtual long GetArea() = 0; // error
7:       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: 2
x x x x x x
x x x x x x
x x x x x x
x x x x x x

(1)Circle (2)Rectangle (3)Square (0)Quit: 3
x x x x x
x x x x x
x x x x x
x x x x x
x 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 workings
of the program are totally unaffected. The only difference is that it would now be
impossible 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 virtual
functions 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 Pure
Virtual 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 derive
from 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 provide
common functionality to all the overridden functions. Listing 13.9 reproduces Listing
13.7, this time with <TT>Shape</TT> as an ADT and with an implementation for the
pure 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 message
printed, 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. Implementing
pure virtual functions.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">1:     //Implementing pure virtual functions
2:
3:     #include &lt;iostream.h&gt;
4:
5:     enum BOOL { FALSE, TRUE };
6:
7:     class Shape
8:     {
9:     public:
10:       Shape(){}
11:       ~Shape(){}
12:       virtual long GetArea() = 0; // error
13:       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 Shape
24:    {
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 Shape
44:    {
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 Rectangle
73:    {
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: 2
x x x x x x
x x x x x x
x x x x x x
x x x x x x
Abstract drawing mechanism!

(1)Circle (2)Rectangle (3)Square (0)Quit: 3
x x x x x
x x x x x
x x x x x
x x x x x
x x x x x
Abstract 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 abstract
data type <TT>Shape</TT> is declared, with all three of its accessor methods declared
to be pure virtual. Note that this is not necessary. If any one were declared pure
virtual, 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 in
the base class.
<H4 ALIGN="CENTER"><A NAME="Heading42"></A><FONT COLOR="#000077">Complex Hierarchies
of Abstraction</FONT></H4>
<P>At times, you will derive ADTs from other ADTs. It may be that you will want to
make 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 same
way, and so you make <TT>Mamma

⌨️ 快捷键说明

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