Like variables, C++ functions are stored in the computer's memory (in the text segment). That means that a function has an address. When a function is called, your C++ program branches to the address of that function and begins executing the statements in the function body.
Since a C++ function has an address, we can declare a pointer variable to store that address. The syntax to declare a pointer to a function is a bit different than the syntax to declare a pointer to a variable, but the concept is similar. A pointer to a variable can be used to to access the value stored in the variable to which it points. A pointer to a function can be used to call the function to which it points.
A declaration for a pointer to a function or static
member function looks like this in C++:
return-type (*pointer-name)(parameter-data-types)
The syntax to declare a pointer to a non-static
member function is slightly different:
return-type (ClassName::*pointer-name)(parameter-data-types)
For example, a declaration for a pointer to a function that takes two integers as arguments and returns a Boolean value would look like this:
bool (*compare)(int, int)
while a declaration for a pointer to a member function of the class Fred
that takes a float
and a char
as arguments and returns an integer would look like this:
int (Fred::*ptr)(float, char)
Note that the names for the pointers are entirely up to the programmer.)
You can obtain the address of a function using the unary &
("address-of") operator. The address can be assigned to a function pointer or (more commonly) can be passed to another function and copied into a function pointer parameter:
compare = &my_function;
Once the pointer compare
contains the address of a function, we can use it to call the function - just use the pointer name exactly like a function name:
if (compare(num1, num2))
{
// Code to execute if the function pointed to by compare returns true
}
Let's say that we want to sort an array of Student
objects in ascending order by the data member name
using the selection sort algorithm. If the sort code is defined in a method of a Course
class that contains an array of Student
objects named class_list
and an integer num_students
that specifies the number of objects in the array that have been filled with valid data, the method might look like this:
void Course::sort_class_list(bool (*compare)(const Student&, const Student&))
{
int i, j, min;
Student temp;
for (i = 0; i < num_students - 1; i++)
{
min = i;
for (j = i + 1; j < num_students; j++)
{
if (compare(class_list[j], class_list[min]))
min = j;
}
temp = class_list[i];
class_list[i] = class_list[min];
class_list[min] = temp;
}
}
In Course.cpp
, we can define a comparison function that will let us check whether one Student object's name
member is less than that of the other:
bool name_less(const Student& s1, const Student& s2)
{
if (strcmp(s1.get_name(), s2.get_name()) < 0)
return true;
else
return false;
}
Notes:
Student
objects passed to it, we can declare each of parameters as a reference to a constant Student
object.strcmp()
. They are also private data, so we need to use the public get_name()
accessor method to access them.We put the prototype for this comparison function in Course.h
, outside the declaration of the Course
class:
bool name_less(const Student&, const Student&);
Once all of this is in place, we can call the sort_class_list()
method on a Course
object, supplying the address of the comparison function as the argument:
course1.sort_class_list(&name_less);
To sort the course's students in a different fashion, no modifications are required to the actual sort()
method. Instead, we can just write another comparison function. For example, if we wanted to be able to sort in descending order by the students' GPA, we could add this function to Course.cpp
(and its prototype to Course.h
):
bool gpa_greater(const Student& s1, const Student& s2)
{
return (s1.get_gpa() > s2.get_gpa());
}
Now the behavior of our sort()
method can vary depending on what comparison function we pass to it:
cout << "Students listed in ascending order by name:\n\n";
course1.sort_class_list(&name_less);
course1.print();
cout << "\nStudents listed in descending order by GPA:\n\n";
course2.sort_class_list(&gpa_greater);
course2.print();
And because the comparison functions are not actually part of the Course
class, it's easy for another programmer to add new comparison functions as desired.
That's just one example of how a pointer to a function can allow you to write code that is more generic and reusable.
Download a full program example, including a makefile and sample data files