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

📄 ch09.htm

📁 一本好的VC学习书,本人就是使用这本书开始学习的vc,希望能对大家有帮助
💻 HTM
📖 第 1 页 / 共 5 页
字号:
and easier to use, and they do a better job of hiding information, as we saw in theprevious example.</P><P>References cannot be reassigned, however. If you need to point first to one objectand then another, you must use a pointer. References cannot be null, so if thereis any chance that the object in question may be null, you must not use a reference.You must use a pointer.</P><P>An example of the latter concern is the operator <TT>new</TT>. If <TT>new</TT>cannot allocate memory on the free store, it returns a null pointer. Since a referencecan't be null, you must not initialize a reference to this memory until you've checkedthat it is not null. The following example shows how to handle this:</P><PRE><FONT COLOR="#0066FF">int *pInt = new int;if (pInt != NULL)int &amp;rInt = *pInt;</FONT></PRE><P>In this example a pointer to int, <TT>pInt</TT>, is declared and initialized withthe memory returned by the operator <TT>new</TT>. The address in <TT>pInt</TT> istested, and if it is not null, <TT>pInt</TT> is dereferenced. The result of dereferencingan <TT>int</TT> variable is an <TT>int</TT> object, and <TT>rInt</TT> is initializedto refer to that object. Thus, <TT>rInt</TT> becomes an alias to the <TT>int</TT>returned by the operator <TT>new</TT>.<BLOCKQUOTE>	<P><HR><B>DO </B>pass parameters by reference whenever possible<B>. DO</B> return by reference	whenever possible. DON'T use pointers if references will work. <B>DO</B> use <TT>const</TT>	to protect references and pointers whenever possible.<B> DON'T </B>return a reference	to a local object. <HR></BLOCKQUOTE><H3 ALIGN="CENTER"><A NAME="Heading42"></A><FONT COLOR="#000077">Mixing Referencesand Pointers</FONT></H3><P>It is perfectly legal to declare both pointers and references in the same functionparameter list, along with objects passed by value. Here's an example:</P><PRE><FONT COLOR="#0066FF">CAT * SomeFunction (Person &amp;theOwner, House *theHouse, int age);</FONT></PRE><P>This declaration says that <TT>SomeFunction</TT> takes three parameters. The firstis a reference to a <TT>Person</TT> object, the second is a pointer to a <TT>house</TT>object, and the third is an integer. It returns a pointer to a <TT>CAT</TT> object.<BLOCKQUOTE>	<P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>The question of where to put the	reference (<TT>&amp;</TT>) or indirection (<TT>*</TT>) operator when declaring these	variables is a great controversy. You may legally write any of the following: <HR></BLOCKQUOTE><PRE><FONT COLOR="#0066FF">1:  CAT&amp;  rFrisky;2:  CAT &amp; rFrisky;3:  CAT  &amp;rFrisky;</FONT></PRE><P>White space is completely ignored, so anywhere you see a space here you may putas many spaces, tabs, and new lines as you like. Setting aside freedom of expressionissues, which is best? Here are the arguments for all three: The argument for case1 is that <TT>rFrisky</TT> is a variable whose name is <TT>rFrisky</TT> and whosetype can be thought of as &quot;reference to <TT>CAT</TT> object.&quot; Thus, thisargument goes, the <TT>&amp;</TT> should be with the type. The counterargument isthat the type is <TT>CAT</TT>. The <TT>&amp;</TT> is part of the &quot;declarator,&quot;which includes the variable name and the ampersand. More important, having the <TT>&amp;</TT>near the <TT>CAT</TT> can lead to the following bug:</P><PRE><FONT COLOR="#0066FF">CAT&amp;  rFrisky, rBoots;</FONT></PRE><P>Casual examination of this line would lead you to think that both <TT>rFrisky</TT>and <TT>rBoots</TT> are references to <TT>CAT</TT> objects, but you'd be wrong. Thisreally says that <TT>rFrisky</TT> is a reference to a <TT>CAT</TT>, and <TT>rBoots</TT>(despite its name) is not a reference but a plain old <TT>CAT</TT> variable. Thisshould be rewritten as follows:</P><PRE><FONT COLOR="#0066FF">CAT    &amp;rFrisky, rBoots;</FONT></PRE><P>The answer to this objection is that declarations of references and variablesshould never be combined like this. Here's the right answer:</P><PRE><FONT COLOR="#0066FF">CAT&amp; rFrisky;CAT  boots;</FONT></PRE><P>Finally, many programmers opt out of the argument and go with the middle position,that of putting the <TT>&amp;</TT> in the middle of the two, as illustrated in case2. Of course, everything said so far about the reference operator (<TT>&amp;</TT>)applies equally well to the indirection operator (<TT>*</TT>). The important thingis to recognize that reasonable people differ in their perceptions of the one trueway. Choose a style that works for you, and be consistent within any one program;clarity is, and remains, the goal. This book will adopt two conventions when declaringreferences and pointers:<DL>	<DD><B>1.</B> Put the ampersand and asterisk in the middle, with a space on either	side.<BR>	<BR>	<B>2.</B> Never declare references, pointers, and variables all on the same line.</DL><H3 ALIGN="CENTER"><A NAME="Heading43"></A><FONT COLOR="#000077">Dont Return a Referenceto an Object that Isnt in Scope!</FONT></H3><P>Once C++ programmers learn to pass by reference, they have a tendency to go hog-wild.It is possible, however, to overdo it. Remember that a reference is always an aliasto some other object. If you pass a reference into or out of a function, be sureto ask yourself, &quot;What is the object I'm aliasing, and will it still exist everytime it's used?&quot;</P><P>Listing 9.13 illustrates the danger of returning a reference to an object thatno longer exists.</P><P><A NAME="Heading44"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.13. Returninga reference to a non-existent object.</B></FONT><PRE><FONT COLOR="#0066FF">1:     // Listing 9.132:      // Returning a reference to an object3:      // which no longer exists4:5:      #include &lt;iostream.h&gt;6:7:      class SimpleCat8:      {9:      public:10:            SimpleCat (int age, int weight);11:            ~SimpleCat() {}12:            int GetAge() { return itsAge; }13:            int GetWeight() { return itsWeight; }14:      private:15:           int itsAge;16:           int itsWeight;17:      };18:19:      SimpleCat::SimpleCat(int age, int weight):20:      itsAge(age), itsWeight(weight) {}21:22:      SimpleCat &amp;TheFunction();23:24:      int main()25:      {26:           SimpleCat &amp;rCat = TheFunction();27:           int age = rCat.GetAge();28:           cout &lt;&lt; &quot;rCat is &quot; &lt;&lt; age &lt;&lt; &quot; years old!\n&quot;;29:     return 0;30:      }31:32:      SimpleCat &amp;TheFunction()33:      {34:           SimpleCat Frisky(5,9);35:           return Frisky;<TT>36: }</TT>Output: Compile error: Attempting to return a reference to a local object!</FONT></PRE><BLOCKQUOTE>	<P><HR><FONT COLOR="#000077"><B>WARNING:</B></FONT><B> </B>This program won't compile on	the Borland compiler. It will compile on Microsoft compilers; however, it should	be noted that it is a bad coding practice. <HR></BLOCKQUOTE><P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>On lines7-17, <TT>SimpleCat</TT> is declared. On line 26, a reference to a <TT>SimpleCat</TT>is initialized with the results of calling <TT>TheFunction()</TT>, which is declaredon line 22 to return a reference to a <TT>SimpleCat</TT>.<BR><BR>The body of <TT>TheFunction()</TT> declares a local object of type <TT>SimpleCat</TT>and initializes its age and weight. It then returns that local object by reference.Some compilers are smart enough to catch this error and won't let you run the program.Others will let you run the program, with unpredictable results.</P><P>When <TT>TheFunction()</TT> returns, the local object, <TT>Frisky</TT>, will bedestroyed (painlessly, I assure you). The reference returned by this function willbe an alias to a non-existent object, and this is a bad thing.<H3 ALIGN="CENTER"><A NAME="Heading46"></A><FONT COLOR="#000077">Returning a Referenceto an Object on the Heap</FONT></H3><P>You might be tempted to solve the problem in Listing 9.13 by having <TT>TheFunction()</TT>create <TT>Frisky</TT> on the heap. That way, when you return from <TT>TheFunction()</TT>,<TT>Frisky</TT> will still exist.</P><P>The problem with this approach is: What do you do with the memory allocated for<TT>Frisky</TT> when you are done with it? Listing 9.14 illustrates this problem.</P><P><A NAME="Heading48"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.14. Memoryleaks.</B></FONT><PRE><FONT COLOR="#0066FF">1:     // Listing 9.142:      // Resolving memory leaks3:      #include &lt;iostream.h&gt;4:5:      class SimpleCat6:      {7:      public:8:              SimpleCat (int age, int weight);9:             ~SimpleCat() {}10:            int GetAge() { return itsAge; }11:            int GetWeight() { return itsWeight; }12:13      private:14:           int itsAge;15:           int itsWeight;16:      };17:18:      SimpleCat::SimpleCat(int age, int weight):19:      itsAge(age), itsWeight(weight) {}20:21:      SimpleCat &amp; TheFunction();22:23:      int main()24:      {25:           SimpleCat &amp; rCat = TheFunction();26:           int age = rCat.GetAge();27:           cout &lt;&lt; &quot;rCat is &quot; &lt;&lt; age &lt;&lt; &quot; years old!\n&quot;;28:           cout &lt;&lt; &quot;&amp;rCat: &quot; &lt;&lt; &amp;rCat &lt;&lt; endl;29:           // How do you get rid of that memory?30:           SimpleCat * pCat = &amp;rCat;31:           delete pCat;32:           // Uh oh, rCat now refers to ??33:     return 0;34:      }35:36:      SimpleCat &amp;TheFunction()37:      {38:           SimpleCat * pFrisky = new SimpleCat(5,9);39:           cout &lt;&lt; &quot;pFrisky: &quot; &lt;&lt; pFrisky &lt;&lt; endl;40:           return *pFrisky;<TT>41: }</TT></FONT><FONT COLOR="#0066FF">Output: pFrisky:  0x2bf4rCat is 5 years old!&amp;rCat: 0x2bf4</FONT></PRE><BLOCKQUOTE>	<P><HR><FONT COLOR="#000077"><B>WARNING:</B></FONT><B> </B>This compiles, links, and appears	to work. But it is a time bomb waiting to go off. <HR></BLOCKQUOTE><P><FONT COLOR="#000077"><TT><B>Anaylss:</B></TT></FONT><TT><B> </B>TheFunction()</TT>has been changed so that it no longer returns a reference to a local variable. Memoryis allocated on the free store and assigned to a pointer on line 38. The addressthat pointer holds is printed, and then the pointer is dereferenced and the <TT>SimpleCat</TT>object is returned by reference.<BR>On line 25, the return of <TT>TheFunction()</TT> is assigned to a reference to <TT>SimpleCat</TT>,and that object is used to obtain the cat's age, which is printed on line 27.</P><P>To prove that the reference declared in <TT>main()</TT> is referring to the objectput on the free store in <TT>TheFunction()</TT>, the address of operator is appliedto <TT>rCat</TT>. Sure enough, it displays the address of the object it refers toand this matches the address of the object on the free store.</P><P>So far, so good. But how will that memory be freed? You can't call <TT>delete</TT>on the reference. One clever solution is to create another pointer and initializeit with the address obtained from <TT>rCat</TT>. This does delete the memory, andplugs the memory leak. One small problem, though: What is <TT>rCat</TT> referringto after line 31? As stated earlier, a reference must always alias an actual object;if it references a null object (as this does now), the program is invalid.<BLOCKQUOTE>	<P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>It cannot be overemphasized that	a program with a reference to a null object may compile, but it is invalid and its	performance is unpredictable. <HR></BLOCKQUOTE><P>There are actually three solutions to this problem. The first is to declare a<TT>SimpleCat</TT> object on line 25, and to return that cat from <TT>TheFunction</TT>by value. The second is to go ahead and declare the <TT>SimpleCat</TT> on the freestore in <TT>TheFunction()</TT>, but have <TT>TheFunction()</TT> return a pointerto that memory. Then the calling function can delete the pointer when it is done.<BR>The third workable solution, and the right one, is to declare the object in the callingfunction and then to pass it to <TT>TheFunction()</TT> by reference.<H3 ALIGN="CENTER"><A NAME="Heading50"></A><FONT COLOR="#000077">Pointer, Pointer,Who Has the Point

⌨️ 快捷键说明

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