📄 ch09.htm
字号:
&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 theiraddresses are printed on lines 12-15.<BR>On line 17, a new variable, <TT>intTwo</TT>, is created and initialized with thevalue <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 areprinted 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 createa reference to an object, but not to a class. You do not write this:</P><PRE><FONT COLOR="#0066FF">int & 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 & 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 & 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 & rCatRef = frisky;</FONT></PRE><P>References to objects are used just like the object itself. Member data and methodsare accessed using the normal class member access operator (<TT>.</TT>), and justas with the built-in types, the reference acts as an alias to the object. Listing9.4 illustrates this.</P><P><A NAME="Heading11"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.4. Referencesto objects.</B></FONT><PRE><FONT COLOR="#0066FF">1: // Listing 9.42: // References to class objects3:4: #include <iostream.h>5:6: class SimpleCat7: {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 & rCat = Frisky;28:29: cout << "Frisky is: ";30: cout << Frisky.GetAge() << " years old. \n";31: cout << "And Frisky weighs: ";32: cout << rCat.GetWeight() << " pounds. \n";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 line26, <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 referto <TT>Frisky</TT>. On lines 30 and 32, the <TT>SimpleCat</TT> accessor methods areaccessed 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 forthe 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>&</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 &rAge = hisAge;</FONT></PRE><P>Example 2</P><PRE><FONT COLOR="#0066FF">CAT boots;CAT &rCatRef = boots;</FONT></PRE><H3 ALIGN="CENTER"><A NAME="Heading14"></A><FONT COLOR="#000077">Null Pointers andNull References</FONT></H3><P>When pointers are not initialized, or when they are deleted, they ought to beassigned 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 consideredan invalid program. When a program is invalid, just about anything can happen. Itcan appear to work, or it can erase all the files on your disk. Both are possibleoutcomes of an invalid program.</P><P>Most compilers will support a null object without much complaint, crashing onlyif you try to use the object in some way. Taking advantage of this, however, is stillnot a good idea. When you move your program to another machine or compiler, mysteriousbugs may develop if you have null objects.<H3 ALIGN="CENTER"><A NAME="Heading15"></A><FONT COLOR="#000077">Passing FunctionArguments by Reference</FONT></H3><P>On Day 5, "Functions," 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 usingreferences. The syntax is different, but the net effect is the same. Rather thana copy being created within the scope of the function, the actual original objectis 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 beingreferred 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 reproducedhere as Listing 9.5, for your convenience.<H3><A NAME="Heading16"></A><FONT COLOR="#000077">Listing 9.5. Demonstrating passingby value.</FONT></H3><PRE><FONT COLOR="#0066FF">1: //Listing 9.5 Demonstrates passing by value2:3: #include <iostream.h>4:5: void swap(int x, int y);6:7: int main()8: {9: int x = 5, y = 10;10:11: cout << "Main. Before swap, x: " << x << " y: " << y << "\n";12: swap(x,y);13: cout << "Main. After swap, x: " << x << " y: " << y << "\n";14: return 0;15: }16:17: void swap (int x, int y)18: {19: int temp;20:21: cout << "Swap. Before swap, x: " << x << " y: " << y << "\n";22:23: temp = x;24: x = y;25: y = temp;26:27: cout << "Swap. After swap, x: " << x << " y: " << y << "\n";28:<TT>29: }</TT></FONT></PRE><PRE><FONT COLOR="#0066FF">Output: Main. Before swap, x: 5 y: 10Swap. Before swap, x: 5 y: 10Swap. After swap, x: 10 y: 5Main. After swap, x: 5 y: 10</FONT></PRE><P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>This programinitializes 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 tothe original values.<H4 ALIGN="CENTER"><A NAME="Heading18"></A><FONT COLOR="#000077">Making swap() Workwith Pointers</FONT></H4><P>When you pass in a pointer, you pass in the address of the object, and thus thefunction can manipulate the value at that address. To make <TT>swap()</TT> changethe actual values using pointers, the function, <TT>swap()</TT>, should be declaredto accept two <TT>int</TT> pointers. Then, by dereferencing the pointers, the valuesof <TT>x</TT> and <TT>y</TT> will, in fact, be swapped. Listing 9.6 demonstratesthis idea.</P><P><A NAME="Heading19"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.6. Passingby reference using pointers.</B></FONT><PRE><FONT COLOR="#0066FF">1: //Listing 9.6 Demonstrates passing by reference2:3: #include <iostream.h>4:5: void swap(int *x, int *y);6:7: int main()8: {9: int x = 5, y = 10;10:11: cout << "Main. Before swap, x: " << x << " y: " << y << "\n";12: swap(&x,&y);13: cout << "Main. After swap, x: " << x << " y: " << y << "\n";14: return 0;15: }1617: void swap (int *px, int *py)18: {19: int temp;20:21: cout << "Swap. Before swap, *px: " << *px << " *py: " << *py << "\n";22:23: temp = *px;24: *px = *py;25: *py = temp;26:27: cout << "Swap. After swap, *px: " << *px << " *py: " << *py << "\n";28:<TT>29: }</TT></FONT><FONT COLOR="#0066FF">Output: Main. Before swap, x: 5 y: 10Swap. Before swap, *px: 5 *py: 10Swap. After swap, *px: 10 *py: 5Main. 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 parameterswill 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 thearguments.<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, thevalue at <TT>px</TT> is assigned to the value at <TT>py</TT>. On line 25, the valuestashed 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 addresswas 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 iscumbersome in two ways. First, the repeated need to dereference the pointers withinthe <TT>swap()</TT> function makes it error-prone and hard to read. Second, the needto pass the address of the variables in the calling function makes the inner workingsof <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 howit works. Passing by pointers takes the burden off of the called function, and putsit 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">1: //Listing 9.7 Demonstrates passing by reference2: // using references!3:4: #include <iostream.h>5:6: void swap(int &x, int &y);7:8: int main()9: {10: int x = 5, y = 10;11:12: cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -