Objectives:
When variable is passed between two functions, it may take one of the three forms: value, pointer and reference. The bottom line is that a variable is changeable or non-changeable by the called function.
C++ programs use call by reference often. It appears in both input parameters and output parameters. It also shows up as the function return type. Our objective is to get a clearer picture of what is this thing and its usage.
Value and Pointer
Call by value and call by pointer have been around for a while. An example below illustrates their differences: the content of the calling variable is not changed (call by value) versus changed (call by pointer). In reality, we do want the call-by-value function cube(i) to return the integer, instead of void. Note that we can have both routines use the same function name (a.k.a. function overloading).
Add Reference
Let's add the call-by-reference version into the program as shown below. We have a compiler error when we try to call cube(i). The error message shows that we have "ambiguous" functions, cube(int) and cube(int &). What does it mean?
When we invoke call-by-value function, we use cube(i). When we invoke call-by-value function, we also use cube(i). So, when the compiler encounters cube(i), it does not know which version of the cube we really want. That's where the error comes in. If we do not use cube(i) in our test program, the program should runs fine. In other words, compiler can take all 3 forms of cube() functions as long as there is no ambiguity about which one to use in each calling cube() instruction. Go ahead and try it.
I comment out the call by value. The main test program runs except that cube(i) is now performing the call by reference.
Reference vs Pointer
From caller's perspective, we want the function to either change or not change our parameters. In the C programming days, we achieve this by call-by-pointer or call-by-value respectively. In C++, we can achieve it by call-by-reference or call-by-value. Of course, we can still use call-by-pointer. But, one less thing to remember is a good thing.
So, why is call by reference better than call by pointer? It is certainly an arguable assertion. But, here is my opinion:
Well, they are the same thing. Pointer is the address of the variable. Reference is also the address.
But, they are different. They are different in function definitions: cube(int *) is completely different with cube(int &). They are also different in calling functions: cube(&i) is completely different from cube(i).
I personally like the call by reference for the simple reason: it simplifies the calling convention. I can always use the variable directly in the calling routine. The variable is changed or not is solely determined by the function's parameter definition. In our example, calling routine always do cube(x). If x is going to be changed by cube, then function cube is defined as cube(int &). Otherwise, it is defined as cube(int).
From a different perspective, the call-by-reference model promotes/simplifies parameter passing of functions. The person who writes the function determines if a parameter be changed or not. Specifying a parameter as "reference" gives function the flexibility to change its value and still keeps the same calling convention.
Reference vs Value
As discussed above, call by reference is a good alternative for changing parameters. So, it is quite capable of replacing call by pointer. How about call by value? Can we achieve call by value with call by reference?
It turns out that call by value semantics can be accomplished by adding const in front of a reference parameter. The calling routine pass a reference, but prohibit the called routine to change its value. Hence, it achieves call by value without copying the parameter. It still need to copy the reference (i.e. address) of the object though.
Discussions:
The above discussion mainly addresses the parameter part of the function. How about a function returns a pointer or returns a reference?