1

I'm trying to implement a callback manager that can register and execute the callbacks from different classes, which each classes are from a different DLL.

Each of these classes derives from a common base class. I know how a single class can make use of a template class like below to register and call its own function, but how can this be applied to use on multiple classes sharing the same callback manager?

Any help will be greatly appreciated.

file: callbacktemplate.h
------------------------
#include <functional>
#include <string>
template <class cInstance>
class cCallBackManager
{
private:
    typedef void (cInstance::*tFunction)();
    typedef std::map<std::string, tFunction> funcMap;
     funcMap i_funcMap;
public:
    void SetFunPointer(std::string funcName, tFunction function)
    {
        i_funcMap.insert(std::pair<std::string, tFunction>(funcName, function));            
    }

    void GetFunPointer(cInstance& obj) //how to call this without knowing the type?
    {
        for (funcMap::iterator it = i_funcMap.begin();it!=i_funcMap.end(); ++it)
        {
            (obj.*(it->second))(); 
        }
    }
};


file:example.h
---------------
#include "callbacktemplate.h"
class A: public base
{
private:
    cCallBackManager<A> callback;
public:
     A()
     {
         callback.SetFunPointer<A>("eventA", &A::testcallback);
         callback.GetFunPointer(&this);   //how to generalize this so this can be called from the callback manager with the class object?
     };
     ~A(){};
     void testCallback();
};

class B: public base
{
private:
    cCallBackManager<B> callback;
public:
     B()
     {
         callback.SetFunPointer<B>("eventB", &B::testcallback);
     };
     ~B(){};
     void testCallback();
};

file: main.cpp
------------------
#include "derived.h"

int main()
{
 A a;
 B b;
 //create a callback manager to execute the callback?
 callbackmgr.execute() //execute all the callback

 return 0;
}

lf not using templatized callback manager, how can i achieve something like SetFunPointer(EVENT_NAME, (Base Class)A::testCallback)?

  • You realize here that the cCallBackManager member or class A is not the same as the cCallBackManager of class B, nor the same as that in main, right? – Michael Graczyk Jul 07 '12 at 05:30
  • yes. My question is how can they share a single callback manager? – Augustine xxx Jul 07 '12 at 06:05
  • The callback manager should be a separate object. Here it would be a local variable in main(). More importantly, I think you should rethink what your "callback manager" really is. Think about its interface before you implement its functions. Notice that you have a "Getxxxx" function that doesn't return anything. What is the caller of your function "Getting?" – Michael Graczyk Jul 07 '12 at 06:24
  • Also you have made the callback manager a template class to enforce type restrictions on its subscribers. You should enforce subscriber types based on the callbacks themselves. Otherwise you will have to derive all your subscribers from the same base type to use the same callback manager. – Michael Graczyk Jul 07 '12 at 06:27
  • getFunPointer will execute the function in A::testCallback when class A gets instantiated. – Augustine xxx Jul 07 '12 at 06:45
  • Im a newbie when it comes to template class. I cant think of a way such that template will not be used to get the correct object type. – Augustine xxx Jul 07 '12 at 06:50
  • Hi michael, for the two approaches you suggested, how do i enforce subscribers based on the callback and if all the subscribers is from the same base class? – Augustine xxx Jul 07 '12 at 07:07
  • There are a lot of ways you can approach it. You could require that all the subscribers (c++ classes) conform to some interface. That would be done by having them all derive from the same base class. For instance, they could have some method that your callback manager knows about, which returns a callback function. Alternatively, you could require that the callback functions themselves fulfill some interface. You can do that by either asking for a specific function pointer, or (better) by asking for a functor (a class that implements the "()" operator). – Michael Graczyk Jul 07 '12 at 10:12
  • If you earn more reputation, we can move this discussion to chat. – Michael Graczyk Jul 07 '12 at 10:12

2 Answers2

1

Thanks guys. I've managed to come up with something with your "pointers". :)

File: cCallBackInterface.h

template<class cClass>
class cCallBackInterface
{
public:
cCallBackInterface(){};
~cCallBackInterface(){};

typedef void (cClass::*Function)();

cCallBackInterface(cClass* obj, Function _Function)
{
    cInstance = obj;
    m_Function = _Function;
}

void execute()
{
     (cInstance->*m_Function)();
}

private:
cClass* cInstance;
Function m_Function;
};

File: base.h

class BaseModel;
typedef cCallBackInterface<BaseModel> CallBackInterface;
typedef void(BaseModel::*basefn)();

class BaseModel 
{
public:
BaseModel(){};
~BaseModel(){};

}
};


class derived : public BaseModel
{
public:
derived(){};
~derived(){};

void dosomething()
{
    cout << "derived class is doing something." << endl;
}


};

File: main.cpp

int main()
{  
derived a;

std::vector<CallBackInterface> callback;

callback.push_back(CallBackInterface(&a, (basefn)(&derived::Adosomething)));

for(int i = 0; i < callback.size(); i++)
    callback[i].execute();

return 0;
}
0

You can look at this question regarding using member-function pointers.

What it boils down to is that you need the instance as well as the mem-func pointer, you cannot have a generic one to be used anywhere.

Community
  • 1
  • 1
slashmais
  • 7,069
  • 9
  • 54
  • 80