Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Callback in C++ to a class member

We have a simple communication library for our customers.

My problem is: How can I save a pointer to a method from a class of our customer?

Library.h is the header file with all the methods our customer need to establish a communication.

library.cpp is our code. Somewhere here i have to save the pointers to the method of the callback function from our customer.

customer.cpp is an example how a customer 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!

like image 509
Sascha Avatar asked Feb 07 '11 08:02

Sascha


People also ask

What is the callback function in C?

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.

How are callbacks implemented in C?

Callbacks in C are usually implemented using function pointers and an associated data pointer. You pass your function on_event() and data pointers to a framework function watch_events() (for example). When an event happens, your function is called with your data and some event-specific data.

How do you declare a callback?

A custom callback function can be created by using the callback keyword as the last parameter. It can then be invoked by calling the callback() function at the end of the function. The typeof operator is optionally used to check if the argument passed is actually a function. console.

What is a callback class?

In the simplest terms a callback is a code that you pass into another method. E.g. you have a class A which calls a method on class B but you need some code running from Class A when it's finished. You put your code in its own new method on class A and you pass the method name in when you call the method on class B.


3 Answers

The basic idea is, you define an abstract Callback class, which actually gets passed to your interface. This one calls back to a function passing a single int parameter:

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

This class allows YOUR implementation to be free from knowledge of the code you need to call back into. Of course, to call into a class, you do need an instantiation of Callback that DOES have knowledge of its target. So you then also provide a templated child class that makes it easy for users of your Library to to bind a method in one of their classes to an instance of the generic 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 an instance of the callback from their class, code would look like this. And the invocation is simple too:

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 then would look like this. Define the abstract callback class, your library class, and the templated utility class that the customer uses to wrap their their class and its callback method with:

// 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{ ... };
like image 70
Chris Becke Avatar answered Sep 20 '22 00:09

Chris Becke


The basic 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 the 'type erasure' idiom).

You can then let your customers derive from your "basic callback" type via a template interface.

For a tutorial, see part 4. on this website. Or take a look at how Boost.Function and Boost.Bind work (they do exactly that, although with a slightly more powerful interface)

like image 40
ltjax Avatar answered Sep 22 '22 00:09

ltjax


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

Suppose I have a function (but this could be a class as well), which needs to call another function passed to it. I define this function like this:

#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;
}

A first example on how to use this is using a global function (or static method), like this:

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

int main()
{
myFunction (myFunPtr);
}

I just pass the function pointer to myFunction.

I can also use a lambda expression, like this:

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

The third example (and which is probably what you want), is to pass a class instance that has defined the function-operator, like this:

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 'references to functions' (function pointers, lambda's and functors).

like image 29
Patrick Avatar answered Sep 20 '22 00:09

Patrick