Getting the work done
Functions
The basic format of all functions found in classes is:
returnType className::functionName(argument list)
{
functionBody;
}
returnType
-
All functions (except the constructor and destructor in classes) must have a return type.
-
Return type can be void but must be declared.
-
Return type can be any of the primitive data types or pointers to structures or classes.
-
You must use the return val; keyword and value syntax to return a value.
-
All return paths from the function MUST return a value of the appropriate type.
The compiler will warn you ("Not all paths return a value.") if you do not do this.
You should pay attention to warnings from the compiler.
-
If the return type is void you can exit from the function at any point with just
the return command.
className::
-
All functions that are defined as part of a class in a class definition file (.h)
must have the class name before the
functionName and separated by two colons. (If you forget this you will get some
strange compiler errors because
even if the function is in the .cpp file it will not be recognized as part of the class.)
functionName
-
Can be anything you want.
-
Try not to be overly verbose, e.g. don’t use something like
calculateTheSumOfSquaresRecursively()
when you can use sumOfSquares()
-
While not required the "traditional" format is to capitalize each word in the
function name except for the first.
-
Should be meaningful, e.g. sumOfSquares() not SOS() or function1().
argumentList
-
All arguments in the format dataType argName.
-
If parentheses are empty the function has no arguments.
Old style function definitions required you to use the word “void”.
You can do that now but it is not required.
-
Try to avoid too many arguments.
functionBody
-
Some say if the function is more than 50 lines it should be broken down
into smaller functions. Others say 25, or 100, etc. Use your own judgement.
-
Old style C required declaring all variables at the beginning of the function
before any other code. You can now declare variables anywhere.
This is good because it lets you declare a variable close to where it will be used.
But, it can be confusing because it may make it difficult to find where a variable
you see being used is actually declared.
Function Prototypes
The purpose of a function prototype is to tell the compiler the correct syntax required to
call the function. That is, the number and type of arguments to be passed to the function
and the function return type. For functions not included in classes this is usually done
at the head of the source code file (see example on the left below). Functions included
in the header file defining a class are the prototypes for all functions found in the
class definition file (.cpp).

While many people use the terms declaration and definition interchangably they
have distinct meanings in C++.
Declaration - Introduces the name of the function. This is the function prototype given at the
beginning of a file or in the header file. You can have many declarations, i.e. each file in a procedure program
needs to prototype the functions it will call or in C++ each file that will use a class will need to include the header
file to get the prototypes.
Definition - where the function code is actually found (in the implementation .cpp file for a class).
You can have only one definition. (This is why you can’t #include a .cpp file.)
Default Arguments to Functions
Suppose you have some function...
void someFunction(int x, double d, char c, long l)
{
// function body here
}
In C++ you can specify default values for each of the arguments by modifying this
function's prototype to be...
void someFunction(int x=0, double d=1.5, char c='a', long l=1)
Now all of the following calls to someFunction are legal. Any variables that
are not specified in a call to the function are automatically assigned the default
value.
someFunction(1, 2.5, ‘z’, 32); // normal calling format
someFunction(1, 2.5, ‘z’); // 3 args (arg l takes default value)
someFunction(1, 2.5); // 2 args (args c and l take default values)
someFunction(1); // 1 arg (args d, c, l take default values)
someFunction(); // 0 args (all take default values)
But, you can not skip any of the arguments in a call to the function. For example,
the following is illegal because the char argument is omitted.
someFunction(1, 2.5, 32); // left out a char argument
Variable Argument Lists
If you declare a function, int function(); with no arguments, in C++ that is
exactly what you get. In ANSI standard C this means a function with any number of
arguments. To get the same thing in C you would have to declare this function as
int function(void);. In C++, you can declare a function that takes any number
of arguments with int function(...);. The example below illustrates how this is
done:

-
You must include the header file <cstdarg> this gives you the ability to
parse out all the arguments.
-
You must have some way of indicating the number of arguments in each call.
-
Pass in the number of args in a call as the first argument as in the example above.
-
Pass in some other indicator such as the format string in a call to printf().
-
In the function use the following global variables and data types defined in cstdarg:
-
va_list to create a list of the arguments.
-
va_start(list, argFirst) to initialize the list to all arguments after argFirst
-
va_arg(list, dataType) to fetch each argument. Note, all args must be
of the same data type unless there is some indication of what each type will be
as in the format specifier string in printf().
-
va_end(list) to clean up after fetching all the arguments
Function Pointers
Functions exist in memory, therefore you can actually locate the address in memory
where a function is and create a pointer to that function. The function pointer
can then be used to call the function. Suppose you have a function:
void myFunction(int x)
{
cout << "x = " << x << endl;
}
You can now declare a pointer to a function with one int argument and returning void,
then set the pointer to point to myFunction, and then call the function using the pointer:
void(*funcPtr)(int); // Declare a function pointer called funcPtr
funcPtr = myFunction; // Store the address of myFunction in the pointer
funcPtr(255); // Call myFunction using the pointer
Some of these function pointer definitions can become quite complex as shown below, but
in the majority of programming instances they are never more complicated than the above
example.
To decipher any of these start from the pointer name and work your way out to the argument
types of the function, the return type, and in some of these examples to the pointer array type.
Virtual Functions
Recall the CShape class with the function virtual void draw() and the sub-classes
that implemented their own version of that function.

-
If a function is declared virtual in a parent class the sub-classes are
forced to implement the function.
-
A good programmer is aware that if you just make sure you add a draw()
function to all sub-classes you override the draw() in the parent class so
virtual is not really needed.
-
A smart programmer also knows:
-
If you reference a CRectangle or a CCircle object with a
CRectangle pointer or a CCircle pointer respectively
there is no problem.
-
You may want to have a Vector of CShape objects and
iterate through the Vector with a CShape reference calling
the draw() function in each.
-
But, if you want to do that and the function in CShape has
not been declared as virtual then the compiler
won’t know which CShape sub-class is being referenced to it
will compile a call to the one in the parent.
This is called Early or Static or Compile Time Binding.
-
If you make the draw() function in the parent class virtual however,
the compiler will create different code and produce what is called
Late or Dynamic or Run-Time Binding. This means when you
call a function the code will check the type of sub-class object
the parent class pointer is pointing to and call the appropriate
sub-class function.
-
The process of treating a sub-class object as if it were an instance
of its’ parent class is called upcasting.