Section 7.1. Defining a Function


7.1. Defining a Function

A function is uniquely represented by a name and a set of operand types. Its operands, referred to as parameters, are specified in a comma-separated list enclosed in parentheses. The actions that the function performs are specified in a block, referred to as the function body. Every function has an associated return type.

As an example, we could write the following function to find the greatest common divisor of two ints:

      // return the greatest common divisor      int gcd(int v1, int v2)      {          while (v2) {              int temp = v2;              v2 = v1 % v2;              v1 = temp;          }          return v1;      } 

Here we define a function named gcd that returns an int and has two int parameters. To call gcd, we must supply two int values and we get an int in return.

Calling a Function

To invoke a function we use the call operator, which is a pair of parentheses. As with any operator, the call operator takes operands and yields a result. The operands to the call operator are the name of the function and a (possibly empty) comma-separated list of arguments. The result type of a call is the return type of the called function, and the result itself is the value returned by the function:

      // get values from standard input      cout << "Enter two values: \n";      int i, j;      cin >> i >> j;      // call gcd on arguments i and j      // and print their greatest common divisor      cout << "gcd: " << gcd(i, j) << endl; 

If we gave this program 15 and 123 as input, the output would be 3.

Calling a function does two things: It initializes the function parameters from the corresponding arguments and transfers control to the function being invoked. Execution of the calling function is suspended and execution of the called function begins. Execution of a function begins with the (implicit) definition and initialization of its parameters. That is, when we invoke gcd, the first thing that happens is that variables of type int named v1 and v2 are created. These variables are initialized with the values passed in the call to gcd. In this case, v1 is initialized by the value of i and v2 by the value of j.

Function Body Is a Scope

The body of a function is a statement block, which defines the function's operation. As usual, the block is enclosed by a pair of curly braces and hence forms a new scope. As with any block, the body of a function can define variables. Names defined inside a function body are accessible only within the function itself. Such variables are referred to as local variables. They are "local" to that function; their names are visible only in the scope of the function. They exist only while the function is executing. Section 7.5 (p. 254) covers local variables in more detail.

Execution completes when a return statement is encountered. When the called function finishes, it yields as its result the value specified in the return statement. After the return is executed, the suspended, calling function resumes execution at the point of the call. It uses the return value as the result of evaluating the call operator and continues processing whatever remains of the statement in which the call was performed.

Parameters and Arguments

Like local variables, the parameters of a function provide named, local storage for use by the function. The difference is that parameters are defined inside the function's parameter list and are initialized by arguments passed to the function when the function is called.

An argument is an expression. It might be a variable, a literal constant or an expression involving one or more operators. We must pass exactly the same number of arguments as the function has parameters. The type of each argument must match the corresponding parameter in the same way that the type of an initializer must match the type of the object it initializes: The argument must have the same type or have a type that can be implicitly converted (Section 5.12, p. 178) to the parameter type. We'll cover how arguments match a parameter in detail in Section 7.8.2 (p. 269).

7.1.1. Function Return Type

The return type of a function can be a built-in type, such as int or double, a class type, or a compound type, such as int& or string*. A return type also can be void, which means that the function does not return a value. The following are example definitions of possible function return types:

      bool is_present(int *, int);       // returns bool      int count(const string &, char);   // returns int      Date &calendar(const char*);       // returns reference to Date      void process();                    // process does not return a value 

A function may not return another function or a built-in array type. Instead, the function may return a pointer to the function or to a pointer to an element in the array:

      // ok: pointer to first element of the array      int *foo_bar() { /* ... */ } 

This function returns a pointer to int and that pointer could point to an element in an array.

We'll learn about function pointers in Section 7.9 (p. 276).

Functions Must Specify a Return Type

It is illegal to define or declare a function without an explicit return type:

      // error: missing return type      test(double v1, double v2) { /* ... */ } 

Eariler versions of C++ would accept this program and implicitly define the return type of test as an int. Under Standard C++, this program is an error.

In pre-Standard C++, a function without an explicit return type was assumed to return an int. C++ programs compiled under earlier, non-standard compilers may still contain functions that implicitly return int.



7.1.2. Function Parameter List

The parameter list of a function can be empty but cannot be omitted. A function with no parameters can be written either with an empty parameter list or a parameter list containing the single keyword void. For example, the following declarations of process are equivalent:

      void process() { /* ... */ }      // implicit void parameter list      void process(void){ /* ... */ }  // equivalent declaration 

A parameter list consists of a comma-separated list of parameter types and (optional) parameter names. Even when the types of two parameters are the same, the type must be repeated:

      int manip(int v1, v2) { /* ... */ }      // error      int manip(int v1, int v2) { /* ... */ }  // ok 

No two parameters can have the same name. Similarly, a variable local to a function may not use the same name as the name of any of the function's parameters.

Names are optional, but in a function definition, normally all parameters are named. A parameter must be named to be used.

Parameter Type-Checking

C++ is a statically typed language (Section 2.3, p. 44). The arguments of every call are checked during compilation.



When we call a function, the type of each argument must be either the same type as the corresponding parameter or a type that can be converted (Section 5.12, p. 178) to that type. The function's parameter list provides the compiler with the type information needed to check the arguments. For example, the function gcd, which we defined on page 226, takes two parameters of type int:

      gcd("hello", "world"); // error: wrong argument types      gcd(24312);            // error: too few arguments      gcd(42, 10, 0);        // error: too many arguments 

Each of these calls is a compile-time error. In the first call, the arguments are of type const char*. There is no conversion from const char* to int, so the call is illegal. In the second and third calls, gcd is passed the wrong number of arguments. The function must be called with two arguments; it is an error to call it with any other number.

But what happens if the call supplies two arguments of type double? Is this call legal?

      gcd(3.14, 6.29);      // ok: arguments are converted to int 

In C++, the answer is yes; the call is legal. In Section 5.12.1 (p. 179) we saw that a value of type double can be converted to a value of type int. This call involves such a conversionwe want to use double values to initialize int objects. Therefore, flagging the call as an error would be too severe. Rather, the arguments are implicitly converted to int (tHRough truncation). Because this conversion might lose precision, most compilers will issue a warning. In this case, the call becomes

      gcd(3, 6); 

and returns a value of 3.

A call that passes too many arguments, omits an argument, or passes an argument of the wrong type almost certainly would result in serious run-time errors. Catching these so-called interface errors at compile time greatly reduces the compile-debug-test cycle for large programs.



C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net