ch04.htm

来自「C++ From Scratch: An Object-Oriented App」· HTM 代码 · 共 1,077 行 · 第 1/4 页

HTM
1,077
字号
</blockquote><p>It is through these member methods that an object of a class achieves its behavior.   <a name="_Toc441891052"></a><a name="_Toc444149702"></a></p><h3> <a name="Heading11">The Size of Objects</a></h3><p>The size of an object is the sum of the sizes of the member variables that   are declared for its class. Thus, if an <tt>int</tt> is 4 bytes and your class   declares three integer member variables, each object is 12 bytes. Functions   have no size. <a name="_Toc444149703"></a><a name="_Toc450554045"></a></p><h2> <a name="Heading12">Files</a></h2><p>You create a class in two steps: First, the interface to the class is declared   in a <i>header file</i>; second, the member methods are created in a <i>source   code file</i>. </p><blockquote>  <hr>  <p><strong>NOTE: </strong> <b>Header file</b>--A text file that contains the     class declaration. Traditionally named with the .h extension</p>  <p> <b>Source file</b>--A text file that contains the source code for the member     methods of a class. Traiditionally named with the .cpp extension</p>  <hr></blockquote><p>The header file typically has an extension of .h or .hpp, and the source code   file has the extension .cpp. So for your <tt>Game</tt> class, you can expect   to find the declaration in the file Game.h and the implementation of the class   methods in Game.cpp. <a name="_Toc444149704"></a><a name="_Toc450554046"></a></p><h2> <a name="Heading13">Constructors</a></h2><p>It is not uncommon for a class to require a bit of setting up before it can   be used. In fact, an object of that class might not be considered valid if it   hasn't been set up properly. C++ provides a special method to set up and initialize   each object, called a <i>constructor, </i>as shown at line 3. </p><p>In this case, you want the constructor to initialize each of the member variables.   For some member variables, you'll <i>hard wire</i> a reasonable value; for example,   you'll keep track of what round of play you are on, and of course, you'll start   with round 1.</p><blockquote>  <hr>  <p><strong>NOTE: </strong> <i>Hard wire</i> is a programming term that means     that the value is written into the code and doesn't change each time you run     the program. </p>  <hr></blockquote><p>For other member variables, you must ask the user to choose an appropriate   starting value. For example, you'll ask the user to tell you whether duplicates   are allowed, how many letters are to be used, and how many positions are to   appear in the secret code.</p><p>A constructor (line 3) has the same name as the class itself, and never has   a return value.</p><blockquote>  <hr>  <p><strong>NOTE: </strong> The absence of a return value does not, in this case,     mean that it returns <tt>void</tt>. Constructors are special: They have no     return value. There are only two types of methods for which this is true--constructors     and destructors. <a name="_Toc444149705"></a></p>  <hr></blockquote><h3> <a name="Heading14">Destructors</a></h3><p>The job of the destructor (line 4) is to tear down the object. This idea will   make more sense after we talk about allocating memory or other resources. For   now, the destructor won't do much, but as a matter of form, if I create a constructor,   I always create a destructor. <a name="_Toc444149706"></a><a name="_Toc450554047"></a></p><h2> <a name="Heading15">Implementing the Methods</a></h2><p>The header file provides the interface. Each of the methods is named, but the   actual implementation is not in this file--it is in the implementation file   (See Listing 4.2).</p><h4> Listing 4.2 Game.cpp</h4><pre><tt>0:  #include "Game.h"</tt><tt>1:  #include &lt;iostream.h&gt;</tt><tt>2:  </tt><tt>3:  </tt><tt>4:  Game::Game():</tt><tt>5:  round(1),</tt><tt>6:  howManyPositions(0),</tt><tt>7:  howManyLetters(0),</tt><tt>8:  duplicatesAllowed(false)</tt><tt>9:  {</tt><tt>10:     enum        BoundedValues  </tt><tt>11:     { </tt><tt>12:        minPos = 2, </tt><tt>13:        maxPos = 10, </tt><tt>14:        minLetters = 2, </tt><tt>15:        maxLetters = 26 </tt><tt>16:     };</tt><tt>17:     bool valid = false;</tt><tt>18:     while ( ! valid )</tt><tt>19:     {</tt><tt>20:        while ( howManyLetters &lt; minLetters </tt><tt>21:           || howManyLetters &gt; maxLetters )</tt><tt>22:        {</tt><tt>23:           cout &lt;&lt; "How many letters? (";</tt><tt>24:           cout &lt;&lt; minLetters &lt;&lt; "-" &lt;&lt; maxLetters &lt;&lt; "): ";</tt><tt>25:           cin &gt;&gt; howManyLetters;</tt><tt>26:           if ( howManyLetters &lt; minLetters </tt><tt>27:              || howManyLetters &gt; maxLetters )</tt><tt>28:           {</tt><tt>29:              cout &lt;&lt; "please enter a number between "; </tt><tt>30:              cout &lt;&lt; minLetters &lt;&lt; " and " &lt;&lt; maxLetters &lt;&lt; endl;</tt><tt>31:           }</tt><tt>32:        }</tt><tt>33:  </tt><tt>34:        while ( howManyPositions &lt; minPos </tt><tt>35:           || howManyPositions &gt; maxPos )</tt><tt>36:        {</tt><tt>37:           cout &lt;&lt; "How many positions? (";</tt><tt>38:           cout &lt;&lt; minPos &lt;&lt; "-" &lt;&lt; maxPos &lt;&lt; "): ";</tt><tt>39:           cin &gt;&gt; howManyPositions;</tt><tt>40:           if ( howManyPositions &lt; minPos </tt><tt>41:              || howManyPositions &gt; maxPos )</tt><tt>42:           {</tt><tt>43:              cout &lt;&lt; "please enter a number between ";</tt><tt>44:              cout &lt;&lt; minPos &lt;&lt;" and " &lt;&lt; maxPos &lt;&lt; endl;</tt><tt>45:           }</tt><tt>46:        }</tt><tt>47:  </tt><tt>48:        char choice = ' ';</tt><tt>49:        while ( choice != 'y' &amp;&amp; choice != 'n' )</tt><tt>50:        {</tt><tt>51:           cout &lt;&lt; "Allow duplicates (y/n)? ";</tt><tt>52:           cin &gt;&gt; choice;</tt><tt>53:        }</tt><tt>54:  </tt><tt>55:        duplicatesAllowed = choice == 'y' ? true : false;</tt><tt>56:  </tt><tt>57:        if ( ! duplicatesAllowed &amp;&amp; </tt><tt>58:           howManyPositions &gt; howManyLetters )</tt><tt>59:        {</tt><tt>60:         cout &lt;&lt; "I can't put " &lt;&lt; howManyLetters;</tt><tt>61:         cout &lt;&lt; " letters in " &lt;&lt; howManyPositions;</tt><tt>62:         cout &lt;&lt; " positions without duplicates! Please try again.\n";</tt><tt>63:         howManyLetters = 0;</tt><tt>64:         howManyPositions = 0;</tt><tt>65:        }</tt><tt>66:        else</tt><tt>67:           valid = true;</tt><tt>68:     }</tt><tt>69:  </tt><tt>70:  </tt><tt>71:  }</tt><tt>72:  </tt><tt>73:  Game::~Game()</tt><tt>74:  {</tt><tt>75:  </tt><tt>76:  }</tt><tt>77:  </tt><tt>78:  void Game::Play()</tt><tt>79:  {</tt><tt>80:  </tt><tt>81:  }</tt></pre><p>Listing 4.3 provides a short driver program that does nothing but instantiate   an object of type <tt>Game</tt>.</p><h4> Listing 4.3 Decryptix.cpp</h4><pre><tt>0: #include &lt;iostream &gt;</tt><tt>1: #include "Game.h"</tt><tt>2: </tt><tt>3: int main()</tt><tt>4: {</tt><tt>5:     Game theGame;</tt><tt>6:     return 0;</tt><tt>8: }<a name="_Toc444149707"></a><a name="_Toc450554048"></a></tt></pre><h2> <a name="Heading16">Including the Header</a></h2><p>The compiler can't know what a <tt>Game</tt> is without the definition, which   is in the header file. To tell the compiler what a <tt>Game</tt> object is,   the first thing you do in the implementation file is to <tt>#include</tt> the   file with the definition of the <tt>Game</tt> class, in this case Game.h (as   shown on line 1 of Listing 4.2).</p><blockquote>  <hr>  <p><strong>NOTE: </strong> It is desirable to minimize the number of header     files that are included in other header files. Having many <tt>include</tt>     statements within a header file can risk the creation of circular references     (a includes b, which includes c, which includes a) that won't compile. This     can also introduce <i>order dependence</i>, which means that the proper execution     of your code depends on files being added in the "correct order." This makes     for code that is difficult to maintain.</p>  <p> There is no limit to the number of header files you might want to include     in implementation files, but keep the includes in your header file to a minimum.     <a name="_Toc444149708"></a><a name="_Toc450554049"></a></p>  <hr></blockquote><h2> <a name="Heading17">Implementing the Constructor</a></h2><p>A member function definition begins with the name of the class, followed by   two colons (the scoping operator), the name of the function, and its parameters.   On line 4 in Listing 4.2, you can see the implementation of the constructor. </p><blockquote>  <hr>  <p><strong> </strong> <b>scope operator</b>--The pair of colons between the     class name and the method</p>  <p> <b>identifier</b>--Any named thing: object, method, class, variable, and     so on </p>  <hr></blockquote><p>Like all methods, the constructor begins with an open brace (<tt>{</tt>) and   ends with a closing brace (<tt>}</tt>). The body of the constructor lies between   the braces. <a name="_Toc444149709"></a><a name="_Toc450554050"></a></p><h2> <a name="Heading18">Initialization</a></h2><p>In the exploration of variables, I talked about the difference between assignment   and initialization. Member variables can be initialized as well. In fact, the   constructor actually executes in two steps:</p><ul>  <li>    <p> Initialization</p>  </li>  <p></p>  <li>    <p> Construction</p>  </li></ul><p></p><p>Construction is accomplished in the body of the constructor. Initialization   is accomplished through the syntax that is shown: After the closing parentheses   on the constructor, add a colon. For each member variable you want to initialize,   write the variable name, followed by the value to which you want to initialize   it (enclosed in parentheses). Note also that you can initialize multiple members   by separating them with commas. There must be no comma after the last initialized   value.</p><p>Thus, on line 5 in Listing 4.3, you see <tt>round</tt> initialized to the value   <tt>1</tt>, <tt>howManyPositions</tt> to the value <tt>0</tt>, <tt>howManyLetters</tt>   to the value <tt>0</tt>, and <tt>duplicatesAllowed</tt> to the value <tt>false</tt>.</p><blockquote>  <hr>  <p><strong>NOTE: </strong> The new line I've placed between each initialized     value is only for the convenience of the programmer. I can just as easily     put them all on one line, separated by spaces:</p>  <hr></blockquote><pre><tt>Game::Game(): </tt><tt>round(1), </tt><tt>howManyPositions(0),          </tt><tt><tt>howManyLetters</tt>(0), </tt><tt><tt>duplicates</tt>Allowed(false)</tt><tt>{</tt></pre><p>All this initialization occurs before the body of the constructor runs, beginning   on line 10 of Listing 4.2 <a name="WhereWasI"></a>.</p><blockquote>  <hr>  <p><strong>NOTE: </strong> We talk of methods or functions running, being executed,     or being called, depending on context. These all mean the same thing: Program     execution branches to the function, beginning at the first line and proceeding     from there until it reaches a return statement.</p>  <hr></blockquote><p>Within the body of the constructor, you see that an enumerated constant, <tt>BoundedValues</tt>,   is created, and a <i>local</i> variable, <tt>valid</tt>, is created and initialized   on line 17.</p><p>This local variable, <tt>valid</tt>, will exist only for the duration of the   constructor. Because this value is needed only temporarily and is not part of   the permanent state of the object (it is not an attribute of the class <tt>Game</tt>),   do not make it a member variable.</p><p>Just as <tt>valid</tt> is a variable that is local to the constructor, the   instance of <tt>Game</tt> that is created in <tt>main()</tt>is local to <tt>main()</tt>   (Listing 4.3, line 5). Declare it like you declare any other variable--by declaring   its type (<tt>Game</tt>), and then the name of the object itself (<tt>theGame</tt>).   You can name the object anything you want, but it is best to name it something   meaningful so that the code can be easily understood.</p><p>By defining this object, you bring it into existence, and that causes the constructor   to be invoked automatically. </p><p>Normally, methods are called <i>explicitly</i>. The constructor, however, is   called <i>implicitly</i> when the object is created, and the destructor is called   implicitly when the object is destroyed. When a method is called implicitly,   the call doesn't appear in your code: It is understood to be the result of another   action. Thus, when you create an object, you implicitly call the constructor;   when you delete an object, you implicitly call the destructor. Not only do you   not have to call these methods explicitly, you are prohibited from doing so.</p><p>There are two ways to see this explicitly. One way is to add a temporary output   line to the constructor and destructor (as shown in Listing 4.4), and to <tt>main() 

⌨️ 快捷键说明

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