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

📄 ch09.htm

📁 vc的电子书
💻 HTM
📖 第 1 页 / 共 5 页
字号:
1:     //Listing 9.7 Demonstrates passing by reference
2:      // 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";
13:             swap(x,y);
14:             cout << "Main. After swap, x: " << x << " y: " << y << "\n";
15:     return 0;
16:           }
17:
18:           void swap (int &rx, int &ry)
19:           {
20:             int temp;
21:
22:                cout << "Swap. Before swap, rx: " << rx << " ry: " << ry << "\n";
23:
24:                temp = rx;
25:                rx = ry;
26:                ry = temp;
27:
28:                cout << "Swap. After swap, rx: " << rx << " ry: " << ry << "\n";
29:
<TT>30: }</TT>
Output: Main. Before swap, x:5 y: 10
Swap. Before swap, rx:5 ry:10
Swap. After swap, rx:10 ry:5
Main. After swap, x:10, y:5
</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT>Just as in the example with
pointers, two variables are declared on line 10 and their values are printed on line
12. On line 13, the function <TT>swap()</TT> is called, but note that <TT>x</TT>
and <TT>y</TT>, not their addresses, are passed. The calling function simply passes
the variables.<BR>
When <TT>swap()</TT> is called, program execution jumps to line 18, where the variables
are identified as references. Their values are printed on line 22, but note that
no special operators are required. These are aliases for the original values, and
can be used as such.</P>
<P>On lines 24-26, the values are swapped, and then they're printed on line 28. Program
execution jumps back to the calling function, and on line 14, the values are printed
in <TT>main()</TT>. Because the parameters to <TT>swap()</TT> are declared to be
references, the values from <TT>main()</TT> are passed by reference, and thus are
changed in <TT>main()</TT> as well.</P>
<P>References provide the convenience and ease of use of normal variables, with the
power and pass-by-reference capability of pointers!
<H3 ALIGN="CENTER"><A NAME="Heading24"></A><FONT COLOR="#000077">Understanding Function
Headers and Prototypes</FONT></H3>
<P>Listing 9.6 shows <TT>swap()</TT> using pointers, and Listing 9.7 shows it using
references. Using the function that takes references is easier, and the code is easier
to read, but how does the calling function know if the values are passed by reference
or by value? As a client (or user) of <TT>swap()</TT>, the programmer must ensure
that <TT>swap()</TT> will, in fact, change the parameters.</P>
<P>This is another use for the function prototype. By examining the parameters declared
in the prototype, which is typically in a header file along with all the other prototypes,
the programmer knows that the values passed into <TT>swap()</TT> are passed by reference,
and thus will be swapped properly.</P>
<P>If <TT>swap()</TT> had been a member function of a class, the class declaration,
also available in a header file, would have supplied this information.</P>
<P>In C++, clients of classes and functions rely on the header file to tell all that
is needed; it acts as the interface to the class or function. The actual implementation
is hidden from the client. This allows the programmer to focus on the problem at
hand and to use the class or function without concern for how it works.</P>
<P>When Colonel John Roebling designed the Brooklyn Bridge, he worried in detail
about how the concrete was poured and how the wire for the bridge was manufactured.
He was intimately involved in the mechanical and chemical processes required to create
his materials. Today, however, engineers make more efficient use of their time by
using well-understood building materials, without regard to how their manufacturer
produced them.</P>
<P>It is the goal of C++ to allow programmers to rely on well-understood classes
and functions without regard to their internal workings. These &quot;component parts&quot;
can be assembled to produce a program, much the same way wires, pipes, clamps, and
other parts are assembled to produce buildings and bridges.</P>
<P>In much the same way that an engineer examines the spec sheet for a pipe to determine
its load-bearing capacity, volume, fitting size, and so forth, a C++ programmer reads
the interface of a function or class to determine what services it provides, what
parameters it takes, and what values it returns.
<H3 ALIGN="CENTER"><A NAME="Heading25"></A><FONT COLOR="#000077">Returning Multiple
Values</FONT></H3>
<P>As discussed, functions can only return one value. What if you need to get two
values back from a function? One way to solve this problem is to pass two objects
into the function, by reference. The function can then fill the objects with the
correct values. Since passing by reference allows a function to change the original
objects, this effectively lets the function return two pieces of information. This
approach bypasses the return value of the function, which can then be reserved for
reporting errors.</P>
<P>Once again, this can be done with references or pointers. Listing 9.8 demonstrates
a function that returns three values: two as pointer parameters and one as the return
value of the function.</P>

<P><A NAME="Heading26"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.8. Returning
values with pointers.</B></FONT>
<PRE><FONT COLOR="#0066FF">
1:     //Listing 9.8
2:     // Returning multiple values from a function
3:
4:     #include &lt;iostream.h&gt;
5:
6:     typedef unsigned short USHORT;
7:
8:     short Factor(USHORT, USHORT*, USHORT*);
9:
10:    int main()
11:    {
12:       USHORT number, squared, cubed;
13:       short error;
14:
15:       cout &lt;&lt; &quot;Enter a number (0 - 20): &quot;;
16:       cin &gt;&gt; number;
17:
18:       error = Factor(number, &amp;squared, &amp;cubed);
19:
20:       if (!error)
21:       {
22:           cout &lt;&lt; &quot;number: &quot; &lt;&lt; number &lt;&lt; &quot;\n&quot;;
23:           cout &lt;&lt; &quot;square: &quot; &lt;&lt; squared &lt;&lt; &quot;\n&quot;;
24:           cout &lt;&lt; &quot;cubed: &quot;  &lt;&lt; cubed   &lt;&lt; &quot;\n&quot;;
25:       }
26:       else
27:       cout &lt;&lt; &quot;Error encountered!!\n&quot;;
28:     return 0;
29:    }
30:
31:    short Factor(USHORT n, USHORT *pSquared, USHORT *pCubed)
32:    {
33:    short Value = 0;
34:       if (n &gt; 20)
35:          Value = 1;
36:       else
37:       {
38:           *pSquared = n*n;
39:           *pCubed = n*n*n;
40:           Value = 0;
41:       }
42:       return Value;
<TT>43: }</TT>
Output: Enter a number (0-20): 3
number: 3
square: 9
cubed: 27
</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>On line
12, <TT>number</TT>, <TT>squared</TT>, and <TT>cubed</TT> are defined as <TT>USHORT</TT>s.
<TT>number</TT> is assigned a value based on user input. This number and the addresses
of <TT>squared</TT> and <TT>cubed</TT> are passed to the function <TT>Factor()</TT>.<BR>
<TT>Factor()</TT>examines the first parameter, which is passed by value. If it is
greater than <TT>20</TT> (the maximum value this function can handle), it sets <TT>return
Value</TT> to a simple error value. Note that the return value from <TT>Function()</TT>
is reserved for either this error value or the value <TT>0</TT>, indicating all went
well, and note that the function returns this value on line 42.</P>
<P>The actual values needed, the square and cube of <TT>number</TT>, are returned
not by using the return mechanism, but rather by changing the pointers that were
passed into the function.</P>
<P>On lines 38 and 39, the pointers are assigned their return values. On line 40,
<TT>return Value</TT> is assigned a success value. On line 41, <TT>return Value</TT>
is returned.</P>
<P>One improvement to this program might be to declare the following:</P>
<PRE><FONT COLOR="#0066FF">enum ERROR_VALUE { SUCCESS, FAILURE};</FONT></PRE>
<P>Then, rather than returning 0 or 1, the program could return <TT>SUCCESS</TT>
or <TT>FAILURE</TT>.
<H4 ALIGN="CENTER"><A NAME="Heading28"></A><FONT COLOR="#000077">Returning Values
by Reference</FONT></H4>
<P>Although Listing 9.8 works, it can be made easier to read and maintain by using
references rather than pointers. Listing 9.9 shows the same program rewritten to
use references and to incorporate the <TT>ERROR</TT> enumeration.</P>

<P><A NAME="Heading29"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.9.Listing
9.8 rewritten using references.</B></FONT>
<PRE><FONT COLOR="#0066FF">
1:     //Listing 9.9
2:      // Returning multiple values from a function
3:      // using references
4:
5:      #include &lt;iostream.h&gt;
6:
7:      typedef unsigned short USHORT;
8:      enum ERR_CODE { SUCCESS, ERROR };
9:
10:      ERR_CODE Factor(USHORT, USHORT&amp;, USHORT&amp;);
11:
12:      int main()
13:      {
14:           USHORT number, squared, cubed;
15:           ERR_CODE result;
16:
17:           cout &lt;&lt; &quot;Enter a number (0 - 20): &quot;;
18:           cin &gt;&gt; number;
19:
20:           result = Factor(number, squared, cubed);
21:
22:           if (result == SUCCESS)
23:           {
24:                 cout &lt;&lt; &quot;number: &quot; &lt;&lt; number &lt;&lt; &quot;\n&quot;;
25:                 cout &lt;&lt; &quot;square: &quot; &lt;&lt; squared &lt;&lt; &quot;\n&quot;;
26:                 cout &lt;&lt; &quot;cubed: &quot;  &lt;&lt; cubed   &lt;&lt; &quot;\n&quot;;
27:           }
28:           else
29:           cout &lt;&lt; &quot;Error encountered!!\n&quot;;
30:     return 0;
31:      }
32:
33:      ERR_CODE Factor(USHORT n, USHORT &amp;rSquared, USHORT &amp;rCubed)
34:      {
35:           if (n &gt; 20)
36:                return ERROR;   // simple error code
37:           else
38:           {
39:                rSquared = n*n;
40:                rCubed = n*n*n;
41:                return SUCCESS;
42:           }
<TT>43: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Enter a number (0 - 20): 3
number: 3
square: 9
cubed: 27
</FONT></PRE>
<P><FONT COLOR="#000077"><TT><B>Anaylsis:</B></TT></FONT><TT><B> </B></TT>Listing
9.9 is identical to 9.8, with two exceptions. The <TT>ERR_CODE</TT> enumeration makes
the error reporting a bit more explicit on lines 36 and 41, as well as the error
handling on line 22.<BR>
<BR>
The larger change, however, is that <TT>Factor()</TT> is now declared to take references
to <TT>squared</TT> and <TT>cubed</TT> rather than to pointers. This makes the manipulation
of these parameters far simpler and easier to understand.
<H3 ALIGN="CENTER"><A NAME="Heading31"></A><FONT COLOR="#000077">Passing by Reference
for Efficiency</FONT></H3>
<P>Each time you pass an object into a function by value, a copy of the object is
made. Each time you return an object from a function by value, another copy is made.</P>
<P>In the &quot;Extra Credit&quot; section at the end of Day 5, you learned that
these objects are copied onto the stack. Doing so takes time and memory. For small
objects, such as the built-in integer values, this is a trivial cost.</P>
<P>However, with larger, user-created objects, the cost is greater. The size of a
user-created object on the stack is the sum of each of its member variables. These,
in turn, can each be user-created objects, and passing such a massive structure by
copying it onto the stack can be very expensive in performance and memory consumption.</P>
<P>There is another cost as well. With the classes you create, each of these temporary
copies is created when the compiler calls a special constructor: the copy constructor.
Tomorrow you will learn how copy constructors work and how you can make your own,
but for now it is enough to know that the copy constructor is called each time a
temporary copy of the object is put on the stack.</P>
<P>When the temporary object is destroyed, which happens when the function returns,
the object's destructor is called. If an object is returned by the function by value,
a copy of that object must be made and destroyed as well.</P>
<P>With large objects, these constructor and destructor calls can be expensive in
speed and use of memory. To illustrate this idea, Listing 9.9 creates a stripped-down
user-created object: <TT>SimpleCat</TT>. A real object would be larger and more expensive,
but this is sufficient to show how often the copy constructor and destructor are
called.</P>
<P>Listing 9.10 creates the <TT>SimpleCat</TT> object and then calls two functions.
The first function receives the <TT>Cat</TT> by value and then returns it by value.
The second one receives a pointer to the object, rather than the object itself, and
returns a pointer to the object.</P>

<P><A NAME="Heading32"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 9.10. Passing
objects by reference.</B></FONT>
<PRE><FONT COLOR="#0066FF">
1:   //Listing 9.10
2:   // Passing pointers to objects
3:
4:   #include &lt;iostream.h&gt;
5:
6:   class SimpleCat
7:   {
8:   public:
9:           SimpleCat ();                    // constructor
10:          SimpleCat(SimpleCat&amp;);     // copy constructor
11:          ~SimpleCat();                    // destructor
12:   };
13:
14:   SimpleCat::SimpleCat()
15:   {
16:          cout &lt;&lt; &quot;Simple Cat Constructor...\n&quot;;
17:   }
18:
19:   SimpleCat::SimpleCat(SimpleCat&amp;)

⌨️ 快捷键说明

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