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

📄 ch09.htm

📁 vc的电子书
💻 HTM
📖 第 1 页 / 共 5 页
字号:
&intOne:              0x213e
&rSomeRef:      0x213e

intOne:                 8
intTwo:                8
rSomeRef:         8
&intOne:              0x213e
&intTwo:              0x2130
&rSomeRef:      0x213e
</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>Once again,
an integer variable and a reference to an integer are declared, on lines 8 and 9.
The integer is assigned the value <TT>5</TT> on line 11, and the values and their
addresses are printed on lines 12-15.<BR>
On line 17, a new variable, <TT>intTwo</TT>, is created and initialized with the
value <TT>8</TT>. On line 18, the programmer tries to reassign <TT>rSomeRef</TT>
to now be an alias to the variable <TT>intTwo</TT>, but that is not what happens.
What actually happens is that <TT>rSomeRef</TT> continues to act as an alias for
<TT>intOne</TT>, so this assignment is exactly equivalent to the following:</P>
<PRE><FONT COLOR="#0066FF">intOne = intTwo;</FONT></PRE>
<P>Sure enough, when the values of <TT>intOne</TT> and <TT>rSomeRef</TT> are printed
(lines 19-21) they are the same as <TT>intTwo</TT>. In fact, when the addresses are
printed on lines 22-24, you see that <TT>rSomeRef</TT> continues to refer to <TT>intOne</TT>
and not <TT>intTwo</TT>.


<BLOCKQUOTE>
	<P>
<HR>
<B>DO </B>use references to create an alias to an object. <B>DO</B> initialize all
	references. <B>DON'T</B> try to reassign a reference. <B>DON'T </B>confuse the address
	of operator with the reference operator. 
<HR>


</BLOCKQUOTE>

<H3 ALIGN="CENTER"><A NAME="Heading10"></A><FONT COLOR="#000077">What Can Be Referenced?</FONT></H3>
<P>Any object can be referenced, including user-defined objects. Note that you create
a reference to an object, but not to a class. You do not write this:</P>
<PRE><FONT COLOR="#0066FF">int &amp; rIntRef = int;    // wrong
</FONT></PRE>
<P>You must initialize <TT>rIntRef</TT> to a particular integer, such as this:</P>
<PRE><FONT COLOR="#0066FF">int howBig = 200;
int &amp; rIntRef = howBig;
</FONT></PRE>
<P>In the same way, you don't initialize a reference to a <TT>CAT</TT>:</P>
<PRE><FONT COLOR="#0066FF">CAT &amp; rCatRef = CAT;   // wrong
</FONT></PRE>
<P>You must initialize <TT>rCatRef</TT> to a particular <TT>CAT</TT> object:</P>
<PRE><FONT COLOR="#0066FF">CAT frisky;
CAT &amp; rCatRef = frisky;
</FONT></PRE>
<P>References to objects are used just like the object itself. Member data and methods
are accessed using the normal class member access operator (<TT>.</TT>), and just
as with the built-in types, the reference acts as an alias to the object. Listing
9.4 illustrates this.</P>

<P><A NAME="Heading11"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.4. References
to objects.</B></FONT>
<PRE><FONT COLOR="#0066FF">
1:    // Listing 9.4
2:    // References to class objects
3:
4:    #include &lt;iostream.h&gt;
5:
6:    class SimpleCat
7:    {
8:       public:
9:          SimpleCat (int age, int weight);
10:         ~SimpleCat() {}
11:         int GetAge() { return itsAge; }
12:         int GetWeight() { return itsWeight; }
13:      private:
14:         int itsAge;
15:         int itsWeight;
16:   };
17:
18:   SimpleCat::SimpleCat(int age, int weight)
19:   {
20:        itsAge = age;
21:        itsWeight = weight;
22:   }
23:
24:   int main()
25:   {
26:        SimpleCat Frisky(5,8);
27:        SimpleCat &amp; rCat = Frisky;
28:
29:        cout &lt;&lt; &quot;Frisky is: &quot;;
30:        cout &lt;&lt; Frisky.GetAge() &lt;&lt; &quot; years old. \n&quot;;
31:        cout &lt;&lt; &quot;And Frisky weighs: &quot;;
32:        cout &lt;&lt; rCat.GetWeight() &lt;&lt; &quot; pounds. \n&quot;;
33:   return 0;
<TT>34: }</TT></FONT></PRE>
<PRE><FONT COLOR="#0066FF">Output: Frisky is: 5 years old.
And Frisky weighs 8 pounds.
</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>On line
26, <TT>Frisky</TT> is declared to be a <TT>SimpleCat</TT> object. On line 27, a
<TT>SimpleCat</TT> reference, <TT>rCat</TT>, is declared and initialized to refer
to <TT>Frisky</TT>. On lines 30 and 32, the <TT>SimpleCat</TT> accessor methods are
accessed by using first the <TT>SimpleCat</TT> object and then the <TT>SimpleCat</TT>
reference. Note that the access is identical. Again, the reference is an alias for
the actual object.
<H3 ALIGN="CENTER"><A NAME="Heading13"></A><FONT COLOR="#000077">References</FONT></H3>
<P>Declare a reference by writing the type, followed by the reference operator (<TT>&amp;</TT>),
followed by the reference name. References must be initialized at the time of creation.
Example 1</P>
<PRE><FONT COLOR="#0066FF">int hisAge;
int &amp;rAge = hisAge;
</FONT></PRE>
<P>Example 2</P>
<PRE><FONT COLOR="#0066FF">CAT boots;
CAT &amp;rCatRef = boots;
</FONT></PRE>
<H3 ALIGN="CENTER"><A NAME="Heading14"></A><FONT COLOR="#000077">Null Pointers and
Null References</FONT></H3>
<P>When pointers are not initialized, or when they are deleted, they ought to be
assigned to <TT>null</TT> (<TT>0</TT>). This is not true for references. In fact,
a reference cannot be null, and a program with a reference to a null object is considered
an invalid program. When a program is invalid, just about anything can happen. It
can appear to work, or it can erase all the files on your disk. Both are possible
outcomes of an invalid program.</P>
<P>Most compilers will support a null object without much complaint, crashing only
if you try to use the object in some way. Taking advantage of this, however, is still
not a good idea. When you move your program to another machine or compiler, mysterious
bugs may develop if you have null objects.
<H3 ALIGN="CENTER"><A NAME="Heading15"></A><FONT COLOR="#000077">Passing Function
Arguments by Reference</FONT></H3>
<P>On Day 5, &quot;Functions,&quot; you learned that functions have two limitations:
Arguments are passed by value, and the return statement can return only one value.</P>
<P>Passing values to a function by reference can overcome both of these limitations.
In C++, passing by reference is accomplished in two ways: using pointers and using
references. The syntax is different, but the net effect is the same. Rather than
a copy being created within the scope of the function, the actual original object
is passed into the function.


<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>If you read the extra credit section
	after Day 5, you learned that functions are passed their parameters on the stack.
	When a function is passed a value by reference (either using pointers or references),
	the address of the object is put on the stack, not the entire object. In fact, on
	some computers the address is actually held in a register and nothing is put on the
	stack. In either case, the compiler now knows how to get to the original object,
	and changes are made there and not in a copy. 
<HR>


</BLOCKQUOTE>

<P>Passing an object by reference allows the function to change the object being
referred to.</P>
<P>Recall that Listing 5.5 in Day 5 demonstrated that a call to the <TT>swap()</TT>
function did not affect the values in the calling function. Listing 5.5 is reproduced
here as Listing 9.5, for your convenience.
<H3><A NAME="Heading16"></A><FONT COLOR="#000077">Listing 9.5. Demonstrating passing
by value.</FONT></H3>
<PRE><FONT COLOR="#0066FF">1:     //Listing 9.5 Demonstrates passing by value
2:
3:      #include &lt;iostream.h&gt;
4:
5:      void swap(int x, int y);
6:
7:      int main()
8:      {
9:        int x = 5, y = 10;
10:
11:        cout &lt;&lt; &quot;Main. Before swap, x: &quot; &lt;&lt; x &lt;&lt; &quot; y: &quot; &lt;&lt; y &lt;&lt; &quot;\n&quot;;
12:        swap(x,y);
13:        cout &lt;&lt; &quot;Main. After swap, x: &quot; &lt;&lt; x &lt;&lt; &quot; y: &quot; &lt;&lt; y &lt;&lt; &quot;\n&quot;;
14:     return 0;
15:     }
16:
17:      void swap (int x, int y)
18:      {
19:        int temp;
20:
21:        cout &lt;&lt; &quot;Swap. Before swap, x: &quot; &lt;&lt; x &lt;&lt; &quot; y: &quot; &lt;&lt; y &lt;&lt; &quot;\n&quot;;
22:
23:        temp = x;
24:        x = y;
25:        y = temp;
26:
27:        cout &lt;&lt; &quot;Swap. After swap, x: &quot; &lt;&lt; x &lt;&lt; &quot; y: &quot; &lt;&lt; y &lt;&lt; &quot;\n&quot;;
28:
<TT>29: }</TT></FONT></PRE>
<PRE><FONT COLOR="#0066FF">Output: Main. Before swap, x: 5 y: 10
Swap. Before swap, x: 5 y: 10
Swap. After swap, x: 10 y: 5
Main. After swap, x: 5 y: 10
</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>This program
initializes two variables in <TT>main()</TT> and then passes them to the <TT>swap()</TT>
function, which appears to swap them. When they are examined again in <TT>main()</TT>,
they are unchanged!<BR>
The problem here is that <TT>x</TT> and <TT>y</TT> are being passed to <TT>swap()</TT>
by value. That is, local copies were made in the function. What you want is to pass
<TT>x</TT> and <TT>y</TT> by reference.</P>
<P>There are two ways to solve this problem in C++: You can make the parameters of
<TT>swap()</TT> pointers to the original values, or you can pass in references to
the original values.
<H4 ALIGN="CENTER"><A NAME="Heading18"></A><FONT COLOR="#000077">Making swap() Work
with Pointers</FONT></H4>
<P>When you pass in a pointer, you pass in the address of the object, and thus the
function can manipulate the value at that address. To make <TT>swap()</TT> change
the actual values using pointers, the function, <TT>swap()</TT>, should be declared
to accept two <TT>int</TT> pointers. Then, by dereferencing the pointers, the values
of <TT>x</TT> and <TT>y</TT> will, in fact, be swapped. Listing 9.6 demonstrates
this idea.</P>

<P><A NAME="Heading19"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.6. Passing
by reference using pointers.</B></FONT>
<PRE><FONT COLOR="#0066FF">
1:     //Listing 9.6 Demonstrates passing by reference
2:
3:      #include &lt;iostream.h&gt;
4:
5:      void swap(int *x, int *y);
6:
7:      int main()
8:      {
9:        int x = 5, y = 10;
10:
11:        cout &lt;&lt; &quot;Main. Before swap, x: &quot; &lt;&lt; x &lt;&lt; &quot; y: &quot; &lt;&lt; y &lt;&lt; &quot;\n&quot;;
12:        swap(&amp;x,&amp;y);
13:        cout &lt;&lt; &quot;Main. After swap, x: &quot; &lt;&lt; x &lt;&lt; &quot; y: &quot; &lt;&lt; y &lt;&lt; &quot;\n&quot;;
14:     return 0;
15:      }
16
17:      void swap (int *px, int *py)
18:      {
19:        int temp;
20:
21:        cout &lt;&lt; &quot;Swap. Before swap, *px: &quot; &lt;&lt; *px &lt;&lt; &quot; *py: &quot; &lt;&lt; *py &lt;&lt; &quot;\n&quot;;
22:
23:        temp = *px;
24:        *px = *py;
25:        *py = temp;
26:
27:        cout &lt;&lt; &quot;Swap. After swap, *px: &quot; &lt;&lt; *px &lt;&lt; &quot; *py: &quot; &lt;&lt; *py &lt;&lt; &quot;\n&quot;;
28:
<TT>29: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Main. Before swap, x: 5 y: 10
Swap. Before swap, *px: 5 *py: 10
Swap. After swap, *px: 10 *py: 5
Main. After swap, x: 10 y: 5
</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>Success!
On line 5, the prototype of <TT>swap()</TT> is changed to indicate that its two parameters
will be pointers to <TT>int</TT> rather than <TT>int</TT> variables. When <TT>swap()</TT>
is called on line 12, the addresses of <TT>x</TT> and <TT>y</TT> are passed as the
arguments.<BR>
On line 19, a local variable, <TT>temp</TT>, is declared in the <TT>swap()</TT> function.
<TT>Temp</TT> need not be a pointer; it will just hold the value of <TT>*px</TT>
(that is, the value of <TT>x</TT> in the calling function) for the life of the function.
After the function returns, <TT>temp</TT> will no longer be needed.</P>
<P>On line 23, <TT>temp</TT> is assigned the value at <TT>px</TT>. On line 24, the
value at <TT>px</TT> is assigned to the value at <TT>py</TT>. On line 25, the value
stashed in <TT>temp</TT> (that is, the original value at <TT>px</TT>) is put into
<TT>py</TT>.</P>
<P>The net effect of this is that the values in the calling function, whose address
was passed to <TT>swap()</TT>, are, in fact, swapped.
<H4 ALIGN="CENTER"><A NAME="Heading21"></A><FONT COLOR="#000077">Implementing swap()
with References</FONT></H4>
<P>The preceding program works, but the syntax of the <TT>swap()</TT> function is
cumbersome in two ways. First, the repeated need to dereference the pointers within
the <TT>swap()</TT> function makes it error-prone and hard to read. Second, the need
to pass the address of the variables in the calling function makes the inner workings
of <TT>swap()</TT> overly apparent to its users.</P>
<P>It is a goal of C++ to prevent the user of a function from worrying about how
it works. Passing by pointers takes the burden off of the called function, and puts
it where it belongs--on the calling function. Listing 9.7 rewrites the <TT>swap()</TT>
function, using references.</P>

<P><A NAME="Heading22"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.7. swap()
rewritten with references.</B></FONT>
<PRE><FONT COLOR="#0066FF">

⌨️ 快捷键说明

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