C++ pointers to functions and callbacks
How to create and use function pointers, including using them in callbacks
As with a data object, the code generated for a function body is placed in memory, so it has an address which means we can have a pointer to it.
Unlike data object pointers, function pointers do not allows us to modify the function code. There are only two things we can do with a function pointer: call it and take its address.
The pointer obtained by taking the address of a function can be used to call the function.
Declaring and using a pointer to a function
In the example code bellow a pointer is set with the address of a function and then used to call the function.
#include <iostream>
#include <string>
// function implementation
void do_something(string message)
{
std::cout << message << std::endl;
}
// declaring a pointer to functions as the one above
void (*fp)(string);
// call the function using the pointer from another function
void do_something_and_more()
{
std::cout << "Let's call the function using the pointer" << std::endl;
fp("upii! it runs");
std::cout << "Done" << std::endl;
}
int main(void)
{
// associating the function address with the function pointer
fp = &do_something;
do_something_and_more();
}
Pointers to functions have arguments declared just like the functions themselves. That’s why the pointer fp
was declared as returning void
and with a string
parameter.
Note that using *
for deferencing and &
to get the address of a function is optional. Consider the following code example.
// fp1 and fp2 both point to do_something function
void (*fp1)(int) = &do_something;
void (*fp2)(int) = do_something;
fp1("it's me!"); // prints "it's me!"
(*fp1)("it's me again!"); // prints "it's me again!"
fp1("it's me!"); // prints "it's me!"
(*fp1)("it's me again!"); // prints "it's me again!"
Function pointers and callbacks
A typical use for function pointers is to pass a callback function as the parameter of another function.
Imagine you have a function that should call another function, let’s call this other function the callback, which is provided as a parameter. By having the callback function as a parameter of the first function allows to call different functions on different calls of the first function. Confused? Don’t worry, it will become clearer in the code example.
A way to implement the callback mechanism is by using a function pointer that is passed as a parameter of another function. Let’s look at a code example.
#include <iostream>
#include <string>
// the callback function
void do_this_when(const char* message)
{
std::cout << "Message: " << message << std::endl;
}
// the function that will use the callback
void i_will_call_you(void (*fp)(const char* message))
{
fp("upii");
}
int main(void)
{
// calling the fucntion
i_will_call_you(do_this_when); // prints "Message: upii"
i_will_call_you(&do_this_when); // also prints "Message: upii"
}
Use cases to this mechanism is in asynchronous programming, where you want to run some code when some event happens, and in libraries.