C ++ callback for class member

We have a simple communication library for our customers.

My problem: how can I save a pointer to a method from our client's class?

Library.h is a header file with all the methods that our client must install for communication.

library.cpp is our code. Somewhere here I have to save pointers to the callback function method from our client.

customer.cpp is an example of how a client uses our library.

library.h:

 // This is the header file what our customer gets class Library { public: template <class Object, class Function> void SetCallback(Object &obj, Function f); }; 

library.cpp:

 struct T_CUSTOMER { Object o; // <- ??? Function f; // <- ??? } customer; void Library::SetCallback(Object &obj, Function f) { //Saving the method from our costumer customer.o = obj; // <- ??? customer.f = f; // <- ??? } void someFunction(void) { // here i want to call the method from the customer customer.o->customer.f(); //<- ??? } 

customer.cpp:

 class AnyCustomerClass { private: Library lib; public: AnyCustomerClass() { //< here the customer sets his method which I should call lib.SetCallback(this, &AnyCustomerClass::callback()); } callback() { // do something } } 

Thanks for any help!

+6
c ++ function methods callback
source share
5 answers

The basic idea is that you define an abstract Callback class that is actually passed to your interface. This returns a function passing one int parameter:

 struct Callback { virtual ~Callback(){} virtual void operator()(int param)=0; }; 

This class allows your implementation to be free from the knowledge of the code you need to call back. Of course, to call the class, you will need an instance of Callback that knows about its purpose. That way, you also provide a template child class that allows users of your library to bind a method in one of its classes to an instance of a common callback: -

 template<class T> class ClassCallback : public Callback { T* _classPtr; typedef void(T::*fncb)(int param); fncb _cbProc; public: ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){} virtual void operator()(int param){ (_classPtr->*_cbProc)(param); } }; 

To create a callback instance from your class, the code would look like this. And the call is also simple:

 struct CMyClass { Library* _theLibrary; CMyClass(Library* init):_theLibrary(init){ Callback* pCB = new ClassCallback<CMyClass>(&myClass,&CMyClass::OnCb); _theLibrary->SetCallback(pCB); } void OnCb(int){ // callback triggered } void Run(){ _theLibrary->DoWork(); } }; 

In summary: Library.h will look like this. Define the abstract callback class, your library class, and the utility utility template class that the client uses to port their class and callback method using:

 // This is the header file what our customer gets struct Callback {... }; class Library { Callback* _pcb; public: void SetCallback(Callback* pcb){_pcb=pcb;} void DoWork(){ int status=0; (*pcb)(status); } ~Library(){delete _pcb;} }; template<class T> struct ClassCallback{ ... }; 
+7
source share

The main idea is to hide the exact type of the object and function ( Object and Function in your code) behind a virtual function call and wrap both in an abstract interface (this is "type erasure", idioms).

You can then let your customers get their โ€œbasic callbackโ€ using the template interface.

For the tutorial, see part 4. on this website . Or see how Boost.Function and Boost.Bind work (they do just that, albeit with a slightly more powerful interface)

+5
source share

The easiest and most flexible way is to use the std :: function.

Suppose I have a function (but it could be a class) that should call another function passed to it. I define this function as follows:

 #include <functional> // defines std::function #include <iostream> typedef std::function<bool(int)> FunctionPtr; void myFunction (const FunctionPtr &functionPtr) { std::cout << "Before" << std::endl; functionPtr(123); std::cout << "After" << std::endl; } 

The first example of using this method is the use of a global function (or a static method), for example:

 bool myFunPtr(int i) { std::cout << "FunPtr:" << i << std::endl; return true; } int main() { myFunction (myFunPtr); } 

I just pass a pointer to the myFunction function.

I can also use a lambda expression, for example:

 int main() { myFunction ([](int i)->bool{std::cout << "Lambda:" << i << std::endl;return true;}); } 

The third example (and which you probably want) should pass an instance of the class that defined the operator function, for example:

 class X { public: X(std::string s) : m_s(s) {} bool operator()(int i) { std::cout << m_s << i << std::endl; return true; } private: std::string m_s; }; int main() { myFunction ([](int i)->bool{std::cout << "Lambda:" << i << std::endl;return true;}); myFunction (myFunPtr); X x1("x1:"); myFunction (x1); X x2("x2:"); myFunction (x2); } 

As you can see, using std :: function, I can pass 3 different types of "function references" (function pointers, lambda and functors).

+3
source share

The code seems to work somehow, but imho the whole design is very suspicious. http://codepad.org/9QDcMJAg

 #include <stdio.h> struct Library { template <class Object,class Function> void SetCallback(Object &obj, Function f); }; struct Object { void Method( void ); }; typedef void (Object::*Function)(void); struct T_CUSTOMER { Object o; Function f; }; T_CUSTOMER customer; template <class Object,class Function> void Library::SetCallback( Object &obj, Function f ) { customer.o = obj; customer.f = f; } void someFunction(void) { (customer.o.*customer.f)(); } struct AnyCustomerClass : Object { Library lib; AnyCustomerClass() { lib.SetCallback( *this, (Function)&AnyCustomerClass::callback ); } void callback(void) { printf( "callback!\n" ); } }; int main( void ) { AnyCustomerClass a; someFunction(); } 
0
source share

Thanks for the answers, but I still have problems with the implementation (I am a normal program in java or in C (microcontoller). I never thought it would be so difficult for me to implement this in C ++))

I like to use Chris Beck's suggestion.

library.h

 // This is the header file what our customer gets struct Callback { virtual void operator()(int param)=0; }; class Library { Callback *cb; public: void SetCallback(Callback*); }; template<class T> class ClassCallback : public Callback { T* _classPtr; typedef void(T::*fncb)(int dwTime); fncb _cbProc; public: ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){} virtual void operator()(int param){ (_classPtr->*_cbProc)(param); } }; 

customer.cpp

 class T_Customer{ private: Library lib; void OnCallback(int param){ printf("Parameter: %i\n",param); } }; public: T_Customer(){ lib.SetCallback(new ClassCallback<T_Customer>(this,&T_Customer::OnCallback)); } }; 

Library.cpp

 void Library::SetCallback(Callback *callback){ cb = callback; } void executeCallback(){ if(cb) (*cb)(); } int main(void){ T_Customer customer; executeCallback(); return 0; } 
0
source share

All Articles