📄 ch05.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD><SCRIPT LANGUAGE="JavaScript"><!--function popUp(pPage) { var fullURL = document.location; var textURL = fullURL.toString(); var URLlen = textURL.length; var lenMinusPage = textURL.lastIndexOf("/"); lenMinusPage += 1; var fullPath = textURL.substring(0,lenMinusPage); popUpWin = window.open('','popWin','resizable=yes,scrollbars=no,width=525,height=394'); figDoc= popUpWin.document; zhtm= '<HTML><HEAD><TITLE>' + pPage + '</TITLE>'; zhtm += '</head>'; zhtm += '<BODY bgcolor="#FFFFFF">'; zhtm += '<IMG SRC="' + fullPath + pPage + '">'; zhtm += '<P><B>' + pPage + '</B>'; zhtm += '</BODY></HTML>'; window.popUpWin.document.write(zhtm); window.popUpWin.document.close(); // Johnny Jackson 4/28/98 }//--> </SCRIPT> <META NAME="Author" Content="Steph Mineart"> <META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1"> <TITLE>C++ From Scratch -- Ch 5 -- Playing The Game</TITLE><link rel="stylesheet" href="/includes/stylesheets/ebooks.css"></head><BODY TEXT="#000000" BGCOLOR="#FFFFFF"><CENTER><H1><IMG SRC="../button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>C++ From Scratch</H1></CENTER><CENTER> <P><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <HR></CENTER><H1 align="center"> 5 <a name="_Toc444312800"></a></H1><h1 align="center"> Playing The Game</h1><ul> <li><a href="#Heading1">Inline Implementation</a> <li><a href="#Heading2">Constant Member Methods</a> <li><a href="#Heading3">Geek SpeakThis entire section needs to be moved to later in this chapter. Thanks. -jThe Signature</a> <li><a href="#Heading4">Passing by Reference and by Value</a> <ul> <li><a href="#Heading5">References and Passing by Reference</a> </ul> <li><a href="#Heading6">Pointers</a> <ul> <li><a href="#Heading7">What is a pointer?</a> <li><a href="#Heading8">Memory Addresses</a> <li><a href="#Heading9">Dereferencing</a> <li><a href="#Heading10">Getting the Operators Straight</a> </ul> <li><a href="#Heading11">Arrays</a> <li><a href="#Heading12">Excursion: Pointers and Constants</a> <ul> <li><a href="#Heading13">Arrays as Pointers</a> <li><a href="#Heading14">Passing the Array as a Pointer</a> </ul> <li><a href="#Heading15">Using ASSERT</a> <ul> <li><a href="#Heading16">How ASSERT Works</a> </ul> <li><a href="#Heading17">Excursion: Macros</a> <ul> <li><a href="#Heading18">Why All the Parentheses?</a> <li><a href="#Heading19">Macros Versus Functions</a> </ul> <li><a href="#Heading20">String Manipulation</a> <ul> <li><a href="#Heading21">Stringizing</a> <li><a href="#Heading22">Concatenation</a> </ul> <li><a href="#Heading23">Predefined Macros</a> <li><a href="#Heading24"> Through the Program Once, by the Numbers</a> </ul><hr size=4><a name="_Toc440589230"></a><a name="_Toc444312799"></a><p>The declaration of the <tt>Game</tt> object builds on the material we've covered so far, and it adds a few new elements you'll need to build a robust class. Let's start by taking a look at the code (see Listing 5.1) and then discussing it in detail.</p><h4> Listing 5.1 Game.h</h4><pre><tt>1: #ifndef GAME_H</tt><tt>2: #define GAME_H</tt><tt>3: </tt><tt>4: #include "definedValues.h"</tt><tt>5: </tt><tt>6: class Game</tt><tt>7: {</tt><tt>8: public:</tt><tt>9: Game();</tt><tt>10: ~Game() {}</tt><tt>11: void Display(const char * charArray) const</tt><tt>12: {</tt><tt>13: cout << charArray << endl;</tt><tt>14: }</tt><tt>15: void Play();</tt><tt>16: const char * GetSolution() const</tt><tt>17: {</tt><tt>18: return solution;</tt><tt>19: }</tt><tt>20: void Score(const char * thisGuess, int & correct, int & position);</tt><tt>21: </tt><tt>22: private:</tt><tt>23: int howMany(const char *, char);</tt><tt>24: char solution[maxPos];</tt><tt>25: int howManyLetters;</tt><tt>26: int howManyPositions;</tt><tt>27: int round;</tt><tt>28: bool duplicates;</tt></pre><p>29: };Once again, you see inclusion guards on line 1, and you now see the naming pattern that I'll use throughout this book. The inclusion guard will typically have the name of the class or file, in all uppercase, followed by the underscore (<tt>_</tt>) and the uppercase letter <i>H</i>. By having a standard for the creation of inclusion guards, you can reduce the likelihood of using the same guard name on two different header files.</p><p>On line 4, we include definedValues.h. As promised, this file will be included throughout the program.</p><p>On line 6, we begin the declaration of the <tt>Game</tt> class. In the public section we see the public interface for this class. Note that the public interface contains only methods, not data; in fact, it contains only those methods that we want to expose to clients of this class. </p><p>On line 9, we see the default constructor, as described in Chapter 4, "Creating Classes," and on line 10, we see the destructor. The destructor, as it is shown here, has an <i>inline</i> implementation, as do <tt>Display()</tt> (lines 11 to 14) and <tt>GetSolution</tt> (lines 16 to 19).</p><h2> <a name="Heading1">Inline Implementation</a></h2><p>Normally, when a function is called, processing literally jumps from the calling function to the called function. </p><p>The processor must stash away information about the current state of the program. It stores this information in an area of memory known as the <i>stack</i>, which is also where local variables are created.</p><blockquote> <hr> <p><strong>NOTE: </strong> The <i>stack</i> is an area of memory in which local variables and other information about the state of the program are stored.</p> <hr></blockquote><p>The processor must also put the parameters to the new function on the stack and adjust the instruction pointer (which keeps track of which instruction will execute next), as illustrated in Figure 5.1. When the function returns, the return value must be popped off the stack, the local variables and other local state from the function must be cleaned up, and the registers must be readjusted to return you to the state you were in before the function call. </p><p><b>Figure 5.1</b><tt><b> </b></tt><i>The instruction pointer.</i></p><p> </p><p>An alternative to a normal function call is to define the function with the keyword <tt>inline</tt>. In this case, the compiler does not create a real function: It copies the code from the inline function directly into the calling function. No jump is made. It is just as if you had written the statements of the called function right into the calling function.</p><p>Note that inline functions can bring a heavy cost. If the function is called 10 times, the inline code is copied into the calling functions each of those 10 times. The tiny improvement in speed you might achieve is more than swamped by the increase in size of the executable program. Even the speed increase might be illusory. First, today's optimizing compilers do a terrific job on their own, and there is almost never a big gain from declaring a function inline. More importantly, though, the increased size brings its own performance cost.</p><p>If the function you are calling is very small, it might still make sense to designate that function as inline. There are two ways to do so. One is to put the keyword <tt>inline</tt> into the definition of the function, before the return value:</p><pre><tt>inline int Game::howMany()</tt></pre><p>An alternative syntax for class member methods is just to define the method right in the declaration of the class itself. Thus, on line 19 you might note that the destructor's implementation is defined right in the declaration. It turns out that this destructor does nothing, so the braces are empty. This is a perfect use of inlining: There is no need to branch out to the destructor, just to take no action. <a name="_Toc444312802"></a></p><h2> <a name="Heading2">Constant Member Methods</a></h2><p>Take a look at <tt>Display</tt> on lines 11-14. After the argument list is the keyword <tt>const</tt>. This use of <tt>const</tt> means, "I promise that this method does not change the object on which you invoke this method," or, in this case, "I promise that <tt>Display()</tt> won't change the <tt>Game</tt> object on which you call <tt>Display()</tt>."</p><p><tt>const</tt> methods attempt to enlist the compiler in helping you to enforce your design decisions. If you believe that a member method ought not change the object (that is, you want the object treated as if it were read-only), declare the method constant. If you then change the object as a result of calling the method, the compiler flags the error, which can save you from having a difficult-to-find bug.</p><h2> <a name="Heading3">Geek SpeakThis entire section needs to be moved to later in this chapter. Thanks. -jThe Signature</a></h2><p>On line 20, we see the <i>signature</i> for the member method <tt>Score()</tt>. The signature of a method is the name (<tt>Score</tt>) and the parameter list. The declaration of a method consists of its signature and its return value (in this case, <tt>void</tt>).</p><blockquote> <hr> <p><strong> </strong> <b>signature</b>--The name and parameter list of a method.</p> <hr></blockquote><p>Before we examine this signature in detail, let's talk about what this method does and what parameters it needs. The responsibility of this method is to examine the player's guess (an array of characters) and to score it on how many letters he correctly found, and of those letters, how many were in the right place.</p><p>Let's take a look at how this will be used. Listing 5.2 shows the <tt>Play()</tt> method, which calls <tt>Score()</tt>.</p><h4> Listing 5.2 The Play Method</h4><pre><tt>0: void Game::Play()</tt><tt>1: {</tt><tt>2: char guess[80];</tt><tt>3: int correct = 0;</tt><tt>4: int position = 0;</tt><tt>5: </tt><tt>6: //...</tt><tt>7: cout << "\nYour guess: ";</tt><tt>8: Display(guess);</tt><tt>9: </tt><tt>10: Score(guess,correct,position);</tt><tt>11: cout << "\t\t" << correct << " correct, " << position</tt><tt>12: << " in position." << endl;</tt><tt>13: }</tt></pre><p>I've elided much of this method (indicated by the <tt>//...</tt> marks), but the code with which we are concerned is shown. We ask the user for his guess and store it in the character array <tt>guess</tt>on line 2. We display <tt>guess</tt> by calling <tt>Dis</tt><tt>play()</tt> on line 8 and passing <tt>guess</tt> in as a parameter. We then we score<tt> </tt>it by calling <tt>Score() </tt>on line 10 and passing in <tt>guess</tt> and two integer variables: <tt>correct</tt> (declared on line 3) and <tt>position</tt> (declared on line 4). Finally, we print the values for <tt>correct</tt> and <tt>position</tt> on lines 11 and 12.</p><p><tt>Score()</tt> adjusts the values of <tt>correct</tt> and <tt>position</tt>. To accomplish this, we must pass in these two variables <i>by reference</i>.</p><h2> <a name="Heading4">Passing by Reference and by Value</a></h2><p>When you pass an object into a method as a parameter to that method, you can pass it either by reference or by value. If you pass it by reference, you are providing that function with access to the object itself. If you pass it by value, you are actually passing in a copy of the object.</p><blockquote> <hr> <p><strong> </strong> <b>passing by reference</b>--Passing an object into a function.</p> <p> <b>passing by value</b>--Passing a copy of an object into a function.</p> <hr></blockquote><p>This distinction is critical. If we pass <tt>correct</tt> and <tt>position</tt> by value, <tt>Score() </tt>cannot make changes to these variables back in <tt>Play()</tt>. Listing 5.3 illustrates a very simple program that shows this problem. </p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -