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

📄 ch09.htm

📁 vc的电子书
💻 HTM
📖 第 1 页 / 共 5 页
字号:
Output: Making a cat...
Simple Cat constructor...
Frisky is 1 years old
Frisky is 5 years old
Calling FunctionTwo...
FunctionTwo. Returning...
Frisky is now 5 years old
Frisky is 5 years old
Simple Cat Destructor...</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Analysis:</B></TT></FONT><TT><B> </B></TT>The output
is identical to that produced by Listing 9.11. The only significant change is that
<TT>FunctionTwo()</TT> now takes and returns a reference to a constant object. Once
again, working with references is somewhat simpler than working with pointers, and
the same savings and efficiency are achieved, as well as the safety provided by using
<TT>const</TT>.
<H3 ALIGN="CENTER"><A NAME="Heading40"></A><FONT COLOR="#000077">const References</FONT></H3>
<P>C++ programmers do not usually differentiate between &quot;constant reference
to a <TT>SimpleCat</TT> object&quot; and &quot;reference to a constant <TT>SimpleCat</TT>
object.&quot; References themselves can never be reassigned to refer to another object,
and so are always constant. If the keyword <TT>const</TT> is applied to a reference,
it is to make the object referred to constant.
<H3 ALIGN="CENTER"><A NAME="Heading41"></A><FONT COLOR="#000077">When to Use References
and When to Use Pointers</FONT></H3>
<P>C++ programmers strongly prefer references to pointers. References are cleaner
and easier to use, and they do a better job of hiding information, as we saw in the
previous example.</P>
<P>References cannot be reassigned, however. If you need to point first to one object
and then another, you must use a pointer. References cannot be null, so if there
is 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 reference
can't be null, you must not initialize a reference to this memory until you've checked
that 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 with
the memory returned by the operator <TT>new</TT>. The address in <TT>pInt</TT> is
tested, and if it is not null, <TT>pInt</TT> is dereferenced. The result of dereferencing
an <TT>int</TT> variable is an <TT>int</TT> object, and <TT>rInt</TT> is initialized
to 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 References
and Pointers</FONT></H3>
<P>It is perfectly legal to declare both pointers and references in the same function
parameter 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 first
is 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 put
as many spaces, tabs, and new lines as you like. Setting aside freedom of expression
issues, which is best? Here are the arguments for all three: The argument for case
1 is that <TT>rFrisky</TT> is a variable whose name is <TT>rFrisky</TT> and whose
type can be thought of as &quot;reference to <TT>CAT</TT> object.&quot; Thus, this
argument goes, the <TT>&amp;</TT> should be with the type. The counterargument is
that 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. This
really 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. This
should 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 variables
should 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 case
2. Of course, everything said so far about the reference operator (<TT>&amp;</TT>)
applies equally well to the indirection operator (<TT>*</TT>). The important thing
is to recognize that reasonable people differ in their perceptions of the one true
way. 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 declaring
references 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 Reference
to 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 alias
to some other object. If you pass a reference into or out of a function, be sure
to ask yourself, &quot;What is the object I'm aliasing, and will it still exist every
time it's used?&quot;</P>
<P>Listing 9.13 illustrates the danger of returning a reference to an object that
no longer exists.</P>

<P><A NAME="Heading44"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.13. Returning
a reference to a non-existent object.</B></FONT>
<PRE><FONT COLOR="#0066FF">
1:     // Listing 9.13
2:      // Returning a reference to an object
3:      // which no longer exists
4:
5:      #include &lt;iostream.h&gt;
6:
7:      class SimpleCat
8:      {
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 lines
7-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 declared
on 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 be
destroyed (painlessly, I assure you). The reference returned by this function will
be 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 Reference
to 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. Memory
leaks.</B></FONT>
<PRE><FONT COLOR="#0066FF">
1:     // Listing 9.14
2:      // Resolving memory leaks
3:      #include &lt;iostream.h&gt;
4:
5:      class SimpleCat
6:      {
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:  0x2bf4
rCat 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. Memory
is allocated on the free store and assigned to a pointer on line 38. The address
that 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 object
put on the free store in <TT>TheFunction()</TT>, the address of operator is applied
to <TT>rCat</TT>. Sure enough, it displays the address of the object it refers to
and this matches the address of the object on the free store.</P>
<P>So

⌨️ 快捷键说明

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