Professional C__ - Marc Gregoire [373]
Function pointers are typed according to the parameter types and return type of compatible functions. One way to work with function pointers is to use the typedef mechanism to assign a type name to the family of functions that have the given characteristics. For example, the following line declares a type called YesNoFcn that represents a pointer to any function that has two int parameters and returns a bool:
typedef bool(*YesNoFcn)(int, int);
Code snippet from FunctionPointers\FunctionPointers.cpp
C++11 introduces the type alias feature which you can use instead of a typedef and which might be more readable. Type aliases are discussed in Chapter 9. The following line is basically the same as the previous typedef line:
using YesNoFcn = bool(*)(int, int);
Now that this new type exists, you could write a function that takes a YesNoFcn as a parameter. For example, the following function accepts two int arrays and their size, as well as a YesNoFcn. It iterates through the arrays in parallel and calls the YesNoFcn on corresponding elements of both arrays, printing a message if the YesNoFcn function returns true. Notice that even though the YesNoFcn is passed in as a variable, it can be called just like a regular function:
void findMatches(int values1[], int values2[], size_t numValues, YesNoFcn inFunc)
{
for (size_t i = 0; i < numValues; i++) {
if (inFunc(values1[i], values2[i])) {
cout << "Match found at position " << i <<
" (" << values1[i] << ", " << values2[i] << ")" << endl;
}
}
}
Code snippet from FunctionPointers\FunctionPointers.cpp
To call the findMatches() function, all you need is any function that adheres to the defined YesNoFcn type — that is, any type that takes in two ints and returns a bool. For example, consider the following function, which returns true if the two parameters are equal:
bool intEqual(int inItem1, int inItem2)
{
return inItem1 == inItem2;
}
Code snippet from FunctionPointers\FunctionPointers.cpp
Because the intEqual() function matches the YesNoFcn type, it can be passed as the final argument to findMatches(), as follows:
int arr1[] = {2, 5, 6, 9, 10, 1, 1};
int arr2[] = {4, 4, 2, 9, 0, 3, 4};
int arrSize = sizeof(arr1) / sizeof(arr1[0]);
cout << "Calling findMatches() using intEqual():" << endl;
findMatches(arr1, arr2, arrSize, &intEqual);
Code snippet from FunctionPointers\FunctionPointers.cpp
Notice that the intEqual() function is passed into the findMatches() function by taking its address. Technically, the & character is optional — if you simply put the function name, the compiler will know that you mean to take its address. The output is as follows:
Calling findMatches() using intEqual():
Match found at position 3 (9, 9)
The benefit of function pointers lies in the fact that findMatches() is a generic function that compares parallel values in two arrays. As it is used above, it compares based on equality. However, since it takes a function pointer, it could compare based on other criteria. For example, the following function also adheres to the definition of a YesNoFcn:
bool bothOdd(int inItem1, int inItem2)
{
return inItem1 % 2 == 1 && inItem2 % 2 == 1;
}
Code snippet from FunctionPointers\FunctionPointers.cpp
The following code calls findMatches() using bothOdd:
cout << "Calling findMatches() using bothOdd():" << endl;
findMatches(arr1, arr2, arrSize, &bothOdd);
Code snippet from FunctionPointers\FunctionPointers.cpp
The output will be:
Calling findMatches() using bothOdd():
Match found at position 3 (9, 9)
Match found at position 5 (1, 3)
By using function pointers, a single function, findMatches(), was customized to different uses based on a parameter, inFunc.
Instead of using these old-style function pointers, you can also use the C++11 std::function which is explained in Chapter 16.
Pointers to Methods and Members
You can create and use pointers to both variables and