clotodex
clotodex

Reputation: 193

C++ multiple callback member functions from different classes without std and boost

I'm new to C++ and I don't want to use any libraries because I want to really understand whats going on internally. Additionally I try to keep my library-use as low as possible (to improve performance and) to make it as platform-independent as possible (without exporting the library).
So all in all I'd like to not use std or boost to solve this problem.

My question:

I have an EventHandler which has a function:

template<class T> void EventHandler::SetCallbackFunction(T* obj, void (T::*mem_fkt)(void));

I have to save the object and the function to call it later.
There are 2 possibilities:

Why these dont work: - The EventHandler can't be a template class because it needs to handle multiple classes.. - void* -> I don't know how to save the classname to cast it later on

How can I do that?
(Or is there another way? Maybe a way to save the classname to cast it later on?)

EDIT:
Furthermore I may need to register multiple callback functions per class so an Interface is not really an option.

class A {
 public:
   void CallbackFktForEventHandler();
   void CallbackFktForAnimationHandler();
   etc...
};

And I know that you could solve it based on something like this:

class A{
  public:
    void Callback();
    static void CallbackStatic(void* self){
      static_cast<A*>->CallBack();
    };
};

But this restricts me too much for my taste.

Upvotes: 4

Views: 2586

Answers (2)

Anedar
Anedar

Reputation: 4275

You could try this:

Create a (pure virtual) base-class that only has one function call():

class Function{
  virtual void call()=0;
}

Create a templated class which stores a function-pointer and an object and make it inherit from Function

template<typename T>
class TemplatedFunction{
  void (T::*m_fkt)(void);
  T* m_obj;

  TemplatedFunction(T* obj, void (T::*fkt)(void)):m_fkt(fkt),m_obj(obj){}

  void call{
    (m_obj->*m_fkt)();
  }
}

And then store pointers to Function in your Event-Handler and just use Function->call()

Try it online: http://ideone.com/3Hu5pw

But you will make your life a lot easier if you use at least the standard library. Basically i would use std::bind to bind your object and your member-function together to a function void()(void) and then store these objects inside a std::vector.

Edit: Oktalist was faster ;)

Upvotes: 4

Oktalist
Oktalist

Reputation: 14714

You can use type erasure. You effective save the type of obj by instantiating a class template which implements a non-template virtual interface. This is essentially how std::function is implemented, so you're just writing your own basic version of std::function.

struct ICallback
{
    virtual void call() = 0;
};

template <class T>
struct Callback : public ICallback
{
    virtual void call() override { (m_obj->*m_func)(); }
    Callback(T *obj, void (T::*func)()) : m_obj(obj), m_func(func) {}
    T *m_obj;
    void (T::*m_func)();
};

template <class T>
std::unique_ptr<ICallback> wrap(T *obj, void (T::*func)())
{
    return std::make_unique<Callback<T>>(obj, func);
}

If you don't want to use std::unique_ptr you can roll your own or use an evil raw owning pointer.

Upvotes: 2

Related Questions