Callbacks are important pattern in C++. TO understand this, lets consider a problem of printing the multiplication table of a number which is inputed by user.
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
class m_table
{
private:
int number;
public:
void generate_table(){
for (int i = 1; i <= 10; i++){
cout << number << " * " << i << " = " << number*i << endl;
}
}
void set_number(int i){
number = i;
}
};
int main()
{
int input;
m_table t;
while (true){
cin >> input;
t.set_number(input);
t.generate_table();
}
return 0;
}
The problem with the above method is that it is not operating system independent. Since, we use cout for presenting the number on terminal, if the library is not available on another machine, the whole program will not work.
So, to get rid of such coupling with OS dependent processing (or displaying of output), the implementation may ask a processing function as well from the main program. So, only main program has to deal with which operating system is is running on and which processing callback it needs to pass to the multiplications table function for the output to be displayed.
- Function pointer can hold an address of one function
- A function object can hold two things, address of the function and address of this pointer which is needed to be passed. In C++, functional (library) is recommneded.
In the below code, the concept of function callbacks in C++ is demostrated.
#include "stdafx.h"
#include <iostream>
#include <vector>
// Functional library for C++ (more powerful that function pointers)
#include <functional>
using namespace std;
//--------------------server code--------------------//
// This call implements a callback pattern
class m_table
{
private:
int number;
public:
//function<> class has operator( ) {} already overloaded in it.
// Since it overloads the (), this is called a functor.
// Any object that overloads () is a functor, function<> is not an exeption
void generate_table(function<void(int, int, int)> callback){
for (int i = 1; i <= 10; i++){
callback(number, i, number*i);
}
}
void set_number(int i){
number = i;
}
};
//-------------------Client code--------------------------//
// Below are the callback templates which a client is free to pass in to the server
void receiver1(int number, int i, int result){
cout << number << " * " << i << " = " << result << endl;
}
void receiver2(int number, int i, int result){
cout << number << " X " << i << " == " << result << endl;
}
class Sample
{
public:
void receiver3(/* const Sample = &this, */ int number, int i, int result){
cout << number << " x " << i << " ~ " << result << endl;
}
};
//Functor: A class overloading () operator
class Sample_functor
{
public:
// Overloaded the () so that the object is passed.
void operator() (int number, int i, int result)
{
cout << number << " x " << i << " -> " << result << endl;
}
}
int main()
{
int input;
m_table t;
while (true){
cin >> input;
t.set_number(input);
//From function pointer (dont do it in C++)
t.generate_table(receiver2); // Here function pointer is passed
Sample s1;
// Bind packs the function pointer, the object this and signature for functions by placeholders.
t.generate_table(bind(&Sample::receiver3, &s1, placeholders::_1, placeholders::_2, placeholders::_3));
// functional takes lambda function pointer also
t.generate_table([](int number, int i, int result){cout << number << " * " << i << " = " << result << endl; });
// When this oject is passed, constructor is called
// destructor is called when the generate_table is done.
t.generate_table(Sample_functor());
}
return 0;
}
In the above code, several types of function pointer has been passed (thus implementing the callbacks)
But one point is ver important, that is bind and placeholders in C++.
bind(&Sample::receiver3, &s1, placeholders::_1, placeholders::_2, placeholders::_3)
Bind packs three things and create a callable object (or a type of function pointer).
- function pointer
- object pointer of the object where the function is defined
- placeholders for the arguments of the function. If some argument is known, supply that value directly.