I'm using a library that has callbacks like this:
void onReceive (Lacewing::Server &Server, Lacewing::Server::Client &Client,
char * Data, int Size) {
/* callback body */
}
Server.onReceive (onReceive); /* to register the handler */
I would like to be able to wrap this in a class that can decide what to do when it receives a packet (observer pattern).
How can I do this with C style callbacks? The library does not define an interface to inherit from.
Thanks
Callback functions are one the most powerful mechanisms in C. A callback function is any code that is passed as an argument to some other code, in such a way that this last code is able to call back, i.e., to execute, the code passed as argument. In C, callback functions are implemented using function pointers.
A callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time [Source : Wiki]. In simple language, If a reference of a function is passed to another function as an argument to call it, then it will be called as a Callback function.
Callbacks need to be static so that they don't have an implicit this parameter as the first argument in their function signature. Save this answer. Show activity on this post. Non-static methods require a 'this' instance, and can only be called upon an object instance.
Note the callback function expression, like a function call, in the definition of the principal function; any argument for the callback function call is passed there. The statement for this function call is: int idr = (*ptr)(id2); Where id2 is an argument.
Since you're using liblacewing, every class has a void * Tag
member provided for user data:
/* class method */
void MyServer::onReceive (Lacewing::Server &Server, Lacewing::Server::Client &Client,
char * Data, int Size)
{
/* callback body - this is inside the class */
}
/* global function wraps the class method */
void onReceive (Lacewing::Server &Server, Lacewing::Server::Client &Client,
char * Data, int Size)
{
((MyServer *) Server.Tag)->onReceive (Server, Client, Data, Size);
}
then:
Server.Tag = myServerInstance; /* set the class instance pointer */
Server.onReceive (::onReceive); /* register the global function */
If I understand you correctly, you could do it 2 different ways.
Assuming that this callback structure is using the Data parameter to allow you to pass your own data to the callback function (a common paradigm), you could do it like this:
class MyProcessingClass
{
public:
MyProcessingClass();
virtual ~MyProcessingClass();
// Do whatever processing in this method
virtual void onReceive(Lacewing::Server &Server, Lacewing::Server::Client &Client);
}
void onReceive (Lacewing::Server &Server, Lacewing::Server::Client &Client,
char * Data, int Size)
{
if ( Data != NULL )
{
MyProcessingClass *handler = reinterpret_cast<MyProcessingClass *>(Data);
handler->onReceive( Server, Client );
}
}
Or, if the data pointer is something you need to process instead of a "user data pointer", you'd probably have to use a singleton, some kind of global variable, or similar. In my experience, this is a less common way to use callbacks, and hopefully isn't what you're dealing with.
MyProcessingClass g_Processor;
MyProcessingClass *GetProcessor()
{
return &g_Processor; // or some other way of getting your instance
}
void onReceive (Lacewing::Server &Server, Lacewing::Server::Client &Client,
char * Data, int Size)
{
MyProcessingClass *handler = GetProcessor();
if ( handler != NULL )
{
handler->onReceive( Server, Client );
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With