vendredi 6 septembre 2013

Callbacks on C++ classes methods

My problem of the day : how to designate a NON STATIC method of any class as a callback (i.e a method triggered by any event), without using Boost and others craps ?

Fortunately I was able to draw inspiration from this page (http://www.partow.net/programming/templatecallback) that offers an interesting template.

Only one problem left: to instantiate the callback object the client must still designate in the template argument type / name the class hosting the method that we wishes to designate as a callback, wich is quite annoying...


Therefore, I propose the following mod, involving inheritance on a callback interface class (BaseCallback) :

template <typename ReturnType, typename Parameter>
class BaseCallback
{
public:

    virtual ReturnType operator()(Parameter parameter) = 0;
    virtual ReturnType execute(Parameter parameter) = 0;
};


template <class Class, typename ReturnType, typename Parameter>
class CallBack : public BaseCallback<ReturnType, Parameter>
{
public:

   typedef ReturnType (Class::*Method)(Parameter);

   CallBack(Class* class_instance, Method method)
   : class_instance_(class_instance),
     method_(method)
   {}

   virtual ReturnType operator()(Parameter parameter)
   {
      return (class_instance_->*method_)(parameter);
   }

   virtual ReturnType execute(Parameter parameter)
   {
      return operator()(parameter);
   }

private:

   Class* class_instance_;
   Method method_;
};


We have now a total decoupling between owner class callback method (client) and the calling class, it does not need to know the definition of the client class :-)


Here is a little example:

class Handler
{
protected:
    CallBack<Handler, void, const std::string&>* m_cb;

public:

    Handler( void )
    {
        m_cb = new CallBack<Handler, void, const std::string&>( this, &Handler::Func );
    }


    void Func( const std::string& a )
    {
        printf( "It works : %s\n", a.c_str() );
    }

    BaseCallback<void, const std::string&>* GetCallback( void )
    {
        return m_cb;
    }

};


class EvtSource
{
protected:

    BaseCallback<void, const std::string&>* m_handler;

public:
    
    
    void RegisterHandler( BaseCallback<void, const std::string&>* p_handler )
    {
        m_handler = p_handler;
    }
    
    void DoSomething( void )
    {
        (*m_handler)( "test01" );
    }
};


int main(int argc, char *argv[])
{
    Handler e;
    
    EvtSource foo;
    foo.RegisterHandler( e.GetCallback() );

    foo.DoSomething();
}

Enjoy ! ;-)

Aucun commentaire:

Enregistrer un commentaire