Registering Class Member for External Callback
Registering callbacks is common design pattern in object oriented
programming. However, since the exact type for a callback function
needs to be known by the registering class, registering member
functions of a class for callback from another class is not trivial.
One simple approach is to declare the member callback function as a
static and then pass in an instance class pointer during function
invocation. The class instance can be passed in as a generic pointer
which is re-casted in the static callback and used as a class pointer.
The following is an example of this approach:
//callback type definition
typedef void (*CallbackFunc_t)(void *);
class Caller{
private:
CallbackFunc_t m_CallbackFunc; //callback pointer
void *m_pUser; //user provided data
public:
void RegisterCallback(CallbackFunc_t pCallback,void *pUser){
m_CallbackFunc=pCallback;
m_pUser=pUser;
}
//test function to call the callback
void Trigger(){
m_CallbackFunc(m_pUser);
}
};
//class with a member callback
class Subscriber{
public:
//constructor
Subscriber(){m_Data=99;}
//callback definition
static void MyCallback(void *pVoid){
Subscriber *pSubscriber=(Subscriber *)pVoid;
cout << pSubscriber->m_Data << "\n";
}
//test function
void Test(){
Caller caller;
caller.RegisterCallback(MyCallback,this);
caller.Trigger();
}
private:
int m_Data;
};
int main(){
Subscriber subscriber;
subscriber.Test();
return 0;
}
Another approch is using templates to keep track of the function type.
The example below uses a somewhat convoluted template based syntax.
//this class calls the subscriber's member callback
template <class T,void (T::*pCallBackFun)(void)> class Caller{
public:
Caller(T *pSub) {m_pSub=pSub;}
//calls the callback
void TriggerCallBack(){
(m_pSub->*pCallBackFun)();
}
private:
T* m_pSub;
};
//class with an internal callback function
class Subscriber{
private:
public:
//internal callback
void CallBack(void){cout << "Internal CallBack Called\n";}
//test function for triggering the callback
void Test(){
//here is where we register the callback
Caller<Subscriber,&Subscriber::CallBack> caller(this);
//trigger the callback
caller.TriggerCallBack();
}
};
//program entry point
int main(){
Subscriber subscriber;
subscriber.Test();
return 0;
}