In some languages, the modules of a program may be called
subroutines
,
procedures
or
functions
. For this topic, C++ uses functions to implement sections of code that are a part of the main program i.e. they are modules. These functions may be contained in a system header file like
Functions are an important tool in C++. They are used to:
enable structured programming
reduce code
capture objectives of the program into modules
create useable and reusable code
increase a programmer's productivity.
Therefore functions should
have a clear cut objective,
be at most one page of printed code,
have a
In order for a C++ programmer to use a function, the following must be done in the program. That is the program must:
define the function,
declare the function,
execute/call the function.
In C++, if a function is:
called (executed), it must have been declared above the call in the program,
declared, it must have been defined within the program (either the same file, in a header file or another file compiled with the program),
defined, it must have been defined outside all functions (either the same file, in a header file or another file compiled with the program).
The construct of the functional definition is:
|
|
outputTypeName functionName(signature)
{
statement(s);
return outputTypeValue;
}
|
|
Notice that there is no semicolon after the functional block end. There are some blocks in C++ that must end in a semicolon but this is not one of them.
The
outputTpeName
may be any system or programmer data type including
void
. If
no
output data type is listed, then a compiling error should occur. The
outputTypeValue
must be of same data type as that of
outputTypeName
. The
outputTypeValue
that
The
functionName
may be any C++ legal variable name (meaning it should
not
be too long, it should
not
be a keyword and it should start with a letter of the alphabet or
The
signature of the function's definition
is
a list of
the respective data type
the order in which they appear from left to right
The variables and their data types are a unit of the signature and each of these units are separated from the others by commas.
The functionName and the signature uniquely define the function while the outputType plays no part in this uniqueness. Two C++ functions with different signatures may have the same name. Functions that have the same name but with different signatures are called overloaded functions . The concept of overloading of functions is an important tool that can increase the productivity of the programmer.
The variables defined within the functional block are not visible outside the block (i.e. they are not accessible outside of the block) and are called local variables . These variables are stored in a part of memory called the stack memory and they are created each time the function is called.
The signature may consist of no data types and therefore the function has no arguments. In this case either nothing is listed between the parentheses or the keyword void can be listed.
Variables in C++ that are defined outside of all functions and all blocks are called
global
variables
. Global variables are stored in a part of memory that is called the
heap
. They may be accessed within any function without being a part of the signature or without the programmer using any explicit coding. Because global variables may be accessed within any function, it is recommended that they
NEVER
be used in properly coded programs that
The top line of the function definition is called the function header . The functional block (braces and the code between the braces) is called the body of the function . When the function header is listed by itself and is followed by a semicolon, then this construct is called the functional prototype .
The construct of the prototype is:
|
|
outputTypeName functionName(signature);
|
|
The outputTypeName and the functionName must match those of the function's definition.
The prototype's signature may be either the same as the signature of the definition or it may be just the data types alone without the arguments (i.e. only the data types are required). However, the data types must be in the same order as in the definition's signature and there must be the same number of data types. Since the arguments of the prototype are formal arguments, they do not have to have the same names as those used in the definition.
When a C++ program is compiled, the functional definition is translated into machine language. Machine language
When a C++ function is called, the argument values are placed in variables in stack memory. In the programming language Pascal, the arguments are placed on the stack from left to right. However, in C++ the arguments are placed on the stack from right to left . The Pascal method executes faster and is the method used as the basis in Windows to define functions that Windows calls. The C++ method is important because it permits functions to be defined that require a right to left storage. (This fact will be of no importance in these lectures.)
Comment: In C++ there are three types of functional arguments.
There are those arguments that pass their values to the stack but the variables
There are those arguments that pass their memory location to the body of the function. Since the body of the function
There are those functions that create another name for the argument and pass the new name into the body of the function and thereby providing an opportunity to get access to the argument and to change its value as well. (This approach uses what are called references i.e. another name for a place in memory.) Sometimes this type of function use is called passing by reference . In order to implement passing by reference the argument in the functional definition and in the prototype are preceded by the reference definition operator: & .
By using arguments of type 2 or type 3 above, it is therefore possible to output values from the function in addition to that which is returned by the outputTypeValue . For example:
Using a pointer:
|
|
void cashTransaction(double *ptrAmount, double *ptrDeposit, double *ptrWithdrawal);
|
|
Using a reference:
|
|
void cashProcessing(double &amount, double &deposit, double &withdrawal);
|
|
The above highlighted statements are
A function must be declared to the compiler in order for the compiler to perform strong type checking between the function call and the function declaration. The compiler's linker will then match the declaration of the function with the definition. A function may be declared using one of the following:
by listing the definition above all calls
by listing the functional prototype above all calls.
Providing for a declaration may also be accomplished by placing it within a header file like tools.h that is then placed in the program above main( ) .
The purpose of the declaration is to ensure strong type checking . That is the compiler will check the arguments in the signature and outputtype of the call with those of the declaration to ensure that they agree. The function's prototype does not occupy separate memory only the function's definition's instructions do.
Note: Some authors use the word declaration for definition and visa versa. Be aware of these differences.
If a function is to be used, it must be called (or executed). The construct of a function call is:
|
|
functionName(signature)
|
|
Notice that no outputType is listed in the function call. However if there is output, the compiler will ensure that the data type of the output used agrees with the declaration's outputType if any. The signature of the function call consists of values, variables or expressions but no data type names. These arguments may have variable names different from those of the declaration or definition but they must agree in data type with those in the signature of the declaration.
The following is an example of the definition of a function:
|
|
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}
double salary(double hoursWorked, double hourlyRate)
{
double grossPay;
grossPay = hoursWorked * hourlyRate;
return grossPay;
}
|
|
The functional prototype could be (notice that no variables need to be listed):
|
|
double salary(double, double);
|
|
A call of the function could be like the following:
|
|
weeklyPay = salary(40, 35.95);
|
|
This call would transfer the values 40 and 35.95 to stack memory where the instructions of the function would take these values into the body of the function. The instructions of the function would be carried out and the return value would be transferred from the variable grossPay on the stack to the memory defined by weeklyPay . If weeklyPay is defined in a block (e.g. in a function) then it would also be on the stack for that code. See salary.cpp .
See EXAMPL2A.CPP . Notice the use of functional prototypes for the declarations, the use of function calls and the functional definitions in this program. (Also notice the internal documentation within the program.) Copy this file to your compiler, compile and run it.
As discussed in the previous sections, to represent the relationship between the program and its modules a graphic is used. This graphic is called a
structure chart
(sometimes called
hierarchy
In a structure chart, the program name is listed on top and each of the functions/modules of the program is listed below in their own block. If Intro() or Conclude() also call other functions, then these additional functions would be represented by additional blocks listed below Intro() and Conclude() . Examples of this will be given below. Since values are not passed to the sub modules or from the called modules to the main program, there are no arrows in this structure chart indicating data transfer.
A flowchart for Exampl2A.CPP is the following:
Notice in the flowchart above the two Predefined-Process symbols in the main flowchart and that each of the modules has its own flowchart.
In the last example, the definitions and the declarations were in the program itself. But as stated previously, it is possible to place the functions in a header file. For example: EXAMPL2B.CPP is the same program except the functional definitions are placed in the header file: tools.h . Link to each of these files and observe the code. Create a C++ program and copy EXAMPL2B.CPP into the C++ program part of the project. Next do a right mouse on the program selection under the Solution Explorer on the right hand side of the compiler. Notice that there is an option to Add Item . One of the choices instead of a C++ source file is a header file . Make this selection. When asked for the name of the header file, use: tools.h . After you have done this, copy the code from the example above into the header file window in the compiler. Now compile and run the program. Notice that this program's output is the same as EXAMPL2A.CPP discussed above. The goal of a programmer should be to develop libraries of functions like those in tools.h and then use them in other programs that you develop.
One of the differences between the flowchart of
EXAMPL2A.CPP
and that of
EXAMPL2B.CPP
is that the actual commands within the functions
Intro( )
and
Conclude( )
may
not
be known by either the designer or the
Notice that the process symbol for
Intro( )
and
Conclude( )
contains the name of the header to
Some C++ projects may consist of more than one C++ program file. This is
By default, all non-static functions are external. External functions may be shared between C++ program files within the project. By this is
While this is true of external functions, static functions are only accessible within the C++ program file where they are defined. To make a function static , the keyword static must be included in the header of the function as in the following:
|
|
static outputType functionName(signature)
{
....
return outputTypeVariable;
}
|
|
While static functions are introduced in this section, this concept is only informational. They will not be used in these lectures but they may be used in some of your future uses of C++.
Sometimes there is a problem with file I/O working with strings which have spaces. One way that this can be