Learn more with dummies

Enter your email to join our mailing list for FREE content right to your inbox. Easy!

Working with Functions in C++

Developers often need the ability to break programs up into smaller chunks that are easier to develop. “Real world” programs can be many of thousands (or millions!) of lines long. Without this ability to divide the program into parts, developing such large programs would quickly become impossible.

C++ allows programmers to divide their code up into chunks known as functions. A function with a simple description and a well-defined interface to the outside world can be written and debugged without worrying about the code that surrounds it.

Overloading function names

C++ allows the programmer to assign the same name to two or more functions. This multiple use of names is known as overloading functions or, simply, overloading.

In general, two functions in a single program cannot share the same name. If they did, C++ would have no way to distinguish them.

However, the name of the function includes the number and type of its arguments. (The name of the function does not include its return argument.) Thus, the following are not the same functions:

void someFunction(void)
// ….perform some function
void someFunction(int n)
// …perform some different function
void someFunction(double d)
// …perform some very different function
void someFunction(int n1, int n2)
// ….do something different yet

C++ still knows that the functions someFunction(void), someFunction(int), someFunction(double), and someFunction(int, int) are not the same. Like so many things that deal with computers, this has an analogy in the human world.

void as an argument type is optional. sumFunction(void) and sumFunction() are the same function. A function has a shorthand name, such as someFunction(). As long as we use the entire name, no one gets confused — no matter how many someFunctions there may be. The full name for one of the someFunctions()is someFunction(int). As long as this full name is unique, no confusion occurs.

A typical application may appear as follows:

int intVariable1, intVariable2; // equivalent to
// int Variable1;
// int Variable2;
double doubleVariable;
// functions are distinguished by the type of
// the argument passed
someFunction(); // calls someFunction(void)
someFunction(intVariable1); // calls someFunction(int)
someFunction(doubleVariable); // calls someFunction(double)
someFunction(intVariable1, intVariable2); // calls
// someFunction(int, int)
// this works for constants as well
someFunction(1); // calls someFunction(int)
someFunction(1.0); // calls someFunction(double)
someFunction(1, 2); // calls someFunction(int, int)

In each case, the type of the arguments matches the full name of the three functions.

The return type is not part of the extended name (also known as the function signature) of the function. The following two functions have the same name and, thus, cannot be part of the same program:

int someFunction(int n); // full name of the function
// is someFunction(int)
double someFunction(int n); // same name

The following is acceptable:

int someFunction(int n);
double d = someFunction(10); // promote returned value

The int returned by someFunction() is promoted into a double. Thus, the following would be confusing:

int someFunction(int n);
double someFunction(int n);
double d = someFunction(10);// promote returned int?
// or use returned double as is

C++ would know whether to use the value returned from the double version of someFunction() or promote the value returned from int version.

Defining function prototypes

The programmer may provide the remainder of a C++ source file, or module, the extended name (the name and functions) during the definition of the function.

A function may be defined anywhere in the module. (A module is another name for a C++ source file.) However, something has to tell main() the full name of the function before it can be called. Consider the following code snippet:

int main(int argc, char* pArgs[])
someFunc(1, 2);
int someFunc(double arg1, int arg2)
// …do something

The call to someFunc() from within main() doesn’t know the full name of the function. It may surmise from the arguments that the name is someFunc(int, int) and that its return type is void; however, as you can see, this is incorrect.

C++ could be less lazy and look ahead to determine the full name of someFunc()s on its own, but it doesn’t. What is needed is some way to inform main() of the full name of someFunc() before it is used. What is needed is a before use function declaration. Some type of prototype is necessary.

A prototype declaration appears the same as a function with no body. In use, a prototype declaration appears as follows:

int someFunc(double, int);
int main(int argc, char* pArgs[])
someFunc(1, 2);
int someFunc(double arg1, int arg2)
// …do something

The prototype declaration tells the world (at least that part of the world after the declaration), that the extended name for someFunc() is someFunction(double, int). The call in main() now knows to cast the 1 to a double before making the call. In addition, main() knows that the value returned by someFunc() is an int.

A function call that returns a value is an expression. As with any other provide expression, you are allowed to throw the value returned by a function.

Variable storage types

Function variables are stored in three different places. Variables declared within a function are said to be local. In the following example, the variable localVariable is local to the function fn():

int globalVariable;
void fn()
int localVariable;
static int staticVariable;

The variable localVariable doesn’t exist until the function fn() is called. localVariable ceases to exist when the function returns. Upon return, whatever value that is stored in localVariable is lost. In addition, only fn() has access to localVariable — other functions cannot reach into the function to access it.

By comparison, the variable globalVariable exists as long as the program is running. All functions have access to globalVariable all of the time.

The static variable staticVariable is something of a mix between a local and a global variable. The variable staticVariable is created when execution first reaches the declaration (roughly, when the function fn() is called). In addition, staticVariable is only accessible within fn(). Unlike localVariable, however, staticVariable continues to exist even after the program returns from fn(). If fn() assigns a value to staticVariable once, it will still be there the next time that fn() is called.

In case anyone asks, there is a fourth type, auto, but today it has the same meaning as local, so just ignore them.