Computer Science - C++
LESSON 7A and B:
A: functions and reference parameters
B: Function Templates
OBJECTIVES: The student will use pass-by-reference arguments to return multiple values from a function.
The student will write functions with default arguments.
The student will write overloaded functions.
The student will use a function template to implement a generalized swap routine.
REFERENCES: Deitel, Harvey M. and Paul J. Deitel. C++ How to Program. Chapter 3.
Lesson 7 - Functions and Reference Parameters
INTRODUCTION: In the previous lesson, you learned to write functions that received values and returned one value. In this lesson you will learn about a very important topic called reference parameters. These types of parameters enable you to return more than one value from a function. In addition, you will learn about other function tools, which enable us to enhance the performance of functions. This lesson completes our study of the syntax of functions and tools for writing functions well. In the next series of lessons, you will fill your functions with control structures to solve more demanding problems.
The key topics for this lesson are:
A. Reference Parameters and Functions
B. Default Arguments
C. Overloaded Functions
D. Function Templates
VOCABULARY: ALIAS
REFERENCE PARAMETERS
DEFAULT ARGUMENTS
ADDRESS OPERATOR
OVERLOADED FUNCTIONS
FUNCTION TEMPLATES
DISCUSSION: A. Reference Parameters and Functions
1. It is often necessary to modify the parameters sent to a function. For example, a swap routine which swaps the contents of two variables is a very useful function. The function will work with the memory locations of two variables and it will swap their contents.
2. Before we look at examples of reference parameters we need to understand the concept of an "alias" and memory addresses. Observe the behavior of the following two programs.
Program 7-1
#include <iostream.h>
main ()
{
int a = 2, b;
b = a; // b now also stores 2
cout << "The address of a = " << &a << endl;
cout << "The address of b = " << &b << endl;
return 0;
}
Run Output (machine dependent):
The address of a = 0x8f7ffff4
The address of b = 0x8f7ffff2
Both variables a and b contain the value 2, but each is located in a different memory location. Notice the use of the address operator (&) which returns the memory address of a variable.
Program 7-2
#include <iostream.h>
main ()
{
int a = 2;
int &b = a; // b is a reference variable
cout << "a = " << a << " b = " << b << endl;
b = 7;
cout << "a = " << a << " b = " << b << endl;
cout << "The address of a = " << &a << endl;
cout << "The address of b = " << &b << endl;
return 0;
}
Run Output:
a = 2 b = 2
a = 7 b = 7
The address of a = 0x8f83fff4
The address of b = 0x8f83fff4
In Program 7-2, the variable b is a reference variable for integer variable a. We have created b as an alias for a. Any reference to b is also a reference to a. Notice that variables a and b are identifiers for the same memory location.
Reference variables must be initialized when they are declared and they cannot be reassigned as aliases to other variables. References can be declared and used within a function (as in Program 7-1) but there is little reason to do so. It makes more sense to just use the local variable instead of an alias.
3. We can now construct a swap routine using reference parameters.
Program 7-3
#include <iostream.h>
void swap (int &, int &); // function prototype
main ()
{
int a = 3, b = 5;
cout << "Before swap: a = " << a << " b = " << b << endl;
swap (a,b); // actual parameters
cout << "After swap: a = " << a << " b = " << b << endl;
return 0;
}
void swap (int &one, int &two) // formal parameters
{
int temp = one;
one = two;
two = temp;
}
Run Output:
Before swap: a = 3 b = 5
After swap: a = 5 b = 3
Here is the sequence of events:
a. When function swap is called, the actual parameters passed to the swap function are the variables a and b in function main.
b. In function swap, the reference parameters &one and &two become alias names for variables a and b in function main. Any changes made to one or two inside of function swap are direct changes to the memory locations named a and b in function main.
4. Reference parameters are often referred to as two-way parameters. Data flows into a function. Changes to this data are sent back out of the function by means of the alias variable.
5. The next example consists of a function which obtains two floats from the keyboard and returns the values to the calling function.
Program 7-4
#include <iostream.h>
void getTwoNumbers (double &, double &);
main ()
{
double x,y;
getTwoNumbers (x,y);
cout << "x = " << x << " y = " << y << endl;
return 0;
}
void getTwoNumbers (double &data1, double &data2)
{
cout << "Enter number 1 ---> ";
cin >> data1;
cout << "Enter number 2 ---> ";
cin >> data2;
}
Run output:
Enter number 1 ---> 2.75
Enter number 2 ---> 9.17
x = 2.75 y = 9.17
6. It is important to note that when a reference parameter is used to receive values into a function, a copy is not made of the information. The function uses a local alias to refer to the memory location of the variable passed to the function. Reference parameters do not involve the overhead of copying data from one memory location to another as is the case with value parameters.
B. Default Arguments
1. C++ allows the user to specify default arguments when declaring a function. Some functions may use a fairly common value as one of its parameters as shown in this example from physics.
float force (float mass, float acceleration = 9.81)
// Newton's 2nd Law: F = ma, a = 9.81 m/s2 on earth
{
return (mass * acceleration);
}
When this function is called, we can feed it both values or just the mass. If the acceleration value is omitted in the function call, the function will use the default 9.81.
force (1), returns 9.81
force (5), returns 49.05
force (70,3.70), returns 259.0
In the last case, the value of 3.70 will override the default 9.81. (The acceleration of gravity on Mars is a = 3.70 m/s2.)
2. The default values must be the right-hand values declared in the parameter list. The values omitted when the function is called must be to the right of any explicit values.
3. Some programmers feel that using default values leads to obscure code. It is probably easier to read code when all the values being fed to a function are listed.
4. However, when we get to the implementation of classes, (Lesson 28), we will initialize objects with default values. The idea of default values is a good one in some situations.
C. Overloaded Functions
1. Overloading is a programming strategy used to code a specific algorithm to work with a variety of data types. This is called Polymorphism. For example, the + operator in C++ is overloaded to add integers, floats, even characters. We would say that the + operator is flexible because it can work with a variety of situations.
2. Some functions will end up solving the same fundamental tasks using different data types. For example, the swap routine would be coded the same to swap integers, floats, and characters. Instead of coding a swapint, swapfloat, and swapchar function, we can overload a swap function in C++.
3. Here is an implementation of an overloaded swap function:
4.
(Demo Program 75)
Program 7-5
#include <iostream.h>
void swap (int &, int &);
void swap (double &, double &);
void swap (char &, char &);
main ()
{
int s = 5, t = 8;
double x = 1.25, y = 6.38;
char c1 = 'j', c2 = 'k';
swap (s,t);
cout << "s = " << s << " t = " << t << endl;
swap (x,y);
cout << "x = " << x << " y = " << y << endl;
swap (c1,c2);
cout << "c1 = " << c1 << " c2 = " << c2 << endl;
return 0;
}
void swap (int &a, int &b) {int temp=a; a=b; b=temp;}
void swap (double &a, double &b) {double temp=a; a=b; b=temp;}
void swap (char &a, char &b) {char temp=a; a=b; b=temp;}
Run output:
s = 8 t = 5
x = 6.38 y = 1.25
c1 = k c2 = j
4. When the swap function is called the compiler selects the proper version depending on the data types in the parameter list.
5. Overloading is a valuable technique that will be learned and applied to operators and classes. You have already been using overloaded stream operators with objects cin and cout. The output operator (<<) works with text constants, integers, doubles, etc. This operator has been overloaded to work with many different data types.
LESSON 7B: functions Templates
D. Function Templates
1. If the code for an overloaded function is identical regardless of the data type used, a single function template can be written to replace the many implementations needed to overload a function. The compiler will take a single template for a function and create the appropriate object code depending on the data type sent to the function.
C++ automatically generates separate template functions to handle each type of call appropriatedly. Thus, defining a single function template defining a whole family of solutions.
All function template definitions begin with the template keyword followed by a list of formal type parameters to the function template enclosed in angle brackets (< and >). Each formal parameter is preceded by the keyworkd typename or keyword class.
(Demo Program 76)
Program 7-6
#include <iostream.h>
template <class dataType>
void swap (dataType &, dataType &);
main ()
{
int s = 5, t = 8;
double x = 1.25, y = 6.38;
char c1 = 'j', c2 = 'k';
swap (s,t);
cout << "s = " << s << " t = " << t << endl;
swap (x,y);
cout << "x = " << x << " y = " << y << endl;
swap (c1,c2);
cout << "c1 = " << c1 << " c2 = " << c2 << endl;
return 0;
}
template <class dataType>
void swap (dataType &a, dataType &b)
{
dataType temp = a; a = b; b = temp;
}
3. The run output for Program 7-6 is the same as Program 7-5. The identifier dataType in the function prototype will assume whatever data type is sent to the function. If the swap routine is called with two integers, then dataType represents int. If two doubles are sent, dataType represents double. Notice that the local variable temp inside of swap is also declared of type dataType .
4. The function template for swap returned no data type. If the return type of the function is dependent on the data type of the incoming parameters we can also make the return type flexible. Here is an example using a squaring function:
template <class someType>
someType square (someType number)
{
return number * number;
}
SUMMARY/REVIEW: The last two lessons have covered the material needed to write functions. We are now ready to deal with larger and more difficult problems using functions in a divide-and-conquer approach. The next lessons move on to the control structures of C++.