cout << " wallet2 = $" << wallet2 << endl;
cout << "Using pointers to swap contents again:\n";
swapp(&wallet1, &wallet2); // pass addresses of variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Trying to use passing by value:\n";
swapv(wallet1, wallet2); // pass values of variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
return 0;
}
void swapr(int & a, int & b) // use references
{
int temp;
temp = a; // use a, b for values of variables
a = b;
b = temp;
}
void swapp(int * p, int * q) // use pointers
{
int temp;
temp = *p; // use *p, *q for values of variables
*p = *q;
*q = temp;
}
void swapv(int a, int b) // try using values
{
int temp;
temp = a; // use a, b for values of variables
a = b;
b = temp;
}
Here’s the output of the program in Listing 8.4:
wallet1 = $300 wallet2 = $350 << original values
Using references to swap contents:
wallet1 = $350 wallet2 = $300 << values swapped
Using pointers to swap contents again:
wallet1 = $300 wallet2 = $350 << values swapped again
Trying to use passing by value:
wallet1 = $300 wallet2 = $350 << swap failed
As you’d expect, the reference and pointer methods both successfully swap the contents of the two wallets, whereas the passing by value method fails.
Program Notes
First, note how each function in Listing 8.4 is called:
swapr(wallet1, wallet2); // pass variables
swapp(&wallet1, &wallet2); // pass addresses of variables
swapv(wallet1, wallet2); // pass values of variables
Passing by reference (swapr(wallet1, wallet2)) and passing by value (swapv(wallet1, wallet2)) look identical. The only way you can tell that swapr() passes by reference is by looking at the prototype or the function definition. However, the presence of the address operator (&) makes it obvious when a function passes by address ((swapp(&wallet1, &wallet2)). (Recall that the type declaration int *p means that p is a pointer to an int and therefore the argument corresponding to p should be an address, such as &wallet1.)
Next, compare the code for the functions swapr() (passing by reference) and swapv() (passing by value). The only outward difference between the two is how the function parameters are declared:
void swapr(int & a, int & b)
void swapv(int a, int b)
The internal difference, of course, is that in swapr() the variables a and b serve as aliases for wallet1 and wallet2, so swapping a and b swaps wallet1 and wallet2. But in swapv(), the variables a and b are new variables that copy the values of wallet1 and wallet2, so swapping a and b has no effect on wallet1 and wallet2.
Finally, compare the functions swapr() (passing a reference) and swapp() (passing a pointer). The first difference is in how the function parameters are declared:
void swapr(int & a, int & b)
void swapp(int * p, int * q)
The second difference is that the pointer version requires using the * dereferencing operator throughout when the function uses p and q.
Earlier, I said you should initialize a reference variable when you define it. A function call initializes its parameters with argument values from the function call. So reference function arguments are initialized to the argument passed by the function call. That is, the following function call initializes the formal parameter a to wallet1 and the formal parameter b to wallet2:
swapr(wallet1, wallet2);
Reference Properties and Oddities
Using reference arguments has several twists you need to know about. First, consider Listing 8.5. It uses two functions to cube an argument. One takes a type double argument, and the other takes a reference to double. The actual code for cubing is purposefully a bit odd to illustrate a point.
Listing 8.5. cubes.cpp
// cubes.cpp -- regular and reference arguments
#include
double cube(double a);
double refcube(double &ra);
int main ()
{
using namespace std;
double x = 3.0;
cout << cube(x);
cout << " = cube of " << x << endl;
cout << refcube(x);
cout << " = cube of " << x << endl;
return 0;
}
double cube(double a)
{
a *= a * a;
return a;
}
double refcube(double &ra)
{
ra *= ra * ra;
return ra;
}
Here is the output of the program in Listing 8.5:
27 = cube of 3
27 = cube of 27
Note that the refcube() function modifies the value of x in main() and cube() doesn’t, which reminds you why passing by value is the norm. The variable a is local to cube(). It is initialized to the value of x, but changing a has no effect on x. But because refcube() uses a reference argument, the changes it makes to ra are actually made to x. If your intent is that a function use the information passed to it without modifying the information, and if you’re using a reference, you should use a constant reference. Here, for example, you should use const in the function prototype and function header:
double refcube(const double &ra);