Sign in to follow this  
Dominik2000

Message system problem

Recommended Posts

I have searched for a very flexible solution for a message/event system. I come to a thread in this forum and implemented the classes:

 

BaseMessage.hpp

#ifndef BASEMESSAGE_HPP
#define BASEMESSAGE_HPP


typedef enum
{
    EXIT_MESSAGE
} MessageTypes;


class BaseMessage
{
public:
    MessageTypes getType() { return m_MessageType; }
    
protected:
    BaseMessage() {}
    virtual ~BaseMessage() {}
    
    void setType(MessageTypes type)
    {
        m_MessageType = type;
    }
private:
    MessageTypes m_MessageType;
};


#endif // BASEMESSAGE_HPP

ExitMessage.hpp

#ifndef EXITMESSAGE_HPP
#define EXITMESSAGE_HPP


#include "BaseMessage.hpp"


class ExitMessage : public BaseMessage
{
public:
    ExitMessage()
    {
        setType(EXIT_MESSAGE);
    }
    
    ~ExitMessage()
    {
        
    }


};


#endif // EXITMESSAGE_HPP

 

HandlerFunctionBase.hpp

#ifndef HANDLERFUNCTIONBASE_HPP
#define HANDLERFUNCTIONBASE_HPP


#include "BaseMessage.hpp"


class HandlerFunctionBase
{
public:
    virtual ~HandlerFunctionBase() {}
    void exec(const BaseMessage& message) { call(message); }
    
private:
    virtual void call(const BaseMessage&) = 0;
};


#endif // HANDLERFUNCTIONBASE_HPP

MemberFunctionHandler.hpp

#ifndef MEMBERFUNCTIONHANDLER_HPP
#define MEMBERFUNCTIONHANDLER_HPP


#include "HandlerFunctionBase.hpp"
#include "BaseMessage.hpp"


template< class T, class MessageT >
class MemberFunctionHandler : public HandlerFunctionBase
{
public:
    typedef void (T::*MemFunc)(const MessageT&);
    MemberFunctionHandler(T *instance, MemFunc function)
    {
        m_pInstance = instance;
        m_Function = function;
    }
    
    void call(const BaseMessage &message)
    {
        (m_pInstance->*m_Function)(static_cast<const MessageT&>(message));
    }
    
private:
    T *m_pInstance;
    MemFunc m_Function;
};


#endif // MEMBERFUNCTIONHANDLER_HPP

MessageSystem.hpp

#ifndef MESSAGESYSTEM_HPP
#define MESSAGESYSTEM_HPP


#include "BaseMessage.hpp"
#include "HandlerFunctionBase.hpp"
#include "MemberFunctionHandler.hpp"


#include <functional>
#include <map>


class MessageSystem
{
public:
    MessageSystem();
    ~MessageSystem();
    
    void push(const BaseMessage& message)
    {
        Handlers::iterator itr = m_Handlers.find(0);
        
        if(itr != m_Handlers.end())
            itr->second->exec(message);
    }
    
    template< class T, class N, class MessageT >
    void subscribe(T *instance, void(N::*memFunc)(const MessageT&))
    {
        m_Handlers[0] = new MemberFunctionHandler< N, MessageT >(instance, memFunc);
    }
    
private:
    typedef std::map< int, HandlerFunctionBase* > Handlers;
    Handlers m_Handlers;
};


#endif // MESSAGESYSTEM_HPP

I thought it's not so difficult but I don't get the subscribe call. Here is my call:

void Engine::initialize()
{
    messages = new MessageSystem();
    
    messages->subscribe(this, &Engine::shutdown);
    
    RenderSystem *renderSystem = new RenderSystem();
    m_Systems.push_back(renderSystem);
    
std::vector<System*>::iterator itr;
for(itr = m_Systems.begin(); itr != m_Systems.end(); itr++)
{
(*itr)->initialize();
        std::cout << "Initialized system: " << (*itr)->getType() << std::endl;
}
}


void Engine::shutdown(ExitMessage *message)
{
    m_bShutdown = true;
}

This is only for test! This error occurs at compile time:

/home/dominik/CLProjects/Cantara/src/Engine.cpp:29:48: error: no matching function for call to ‘MessageSystem::subscribe(Engine* const, void (Engine::*)(ExitMessage*))’

But why? I don't get it.

 

Another question, is this a good approach, or should I use another?

 

Dominik

 
 
 

Share this post


Link to post
Share on other sites

Note the two lines:

 

template< class T, class N, class MessageT >
    void subscribe(T *instance, void(N::*memFunc)(const MessageT&))

 

void Engine::shutdown(ExitMessage *message)

 

And the error:

 

MessageSystem::subscribe(Engine* const, void (Engine::*)(ExitMessage*))

 

Passing a function which takes a pointer to the message to a function which wants a const reference taint gonna work... :)

 

 

As to alternatives, this is not my favorite style and I tend to use Boost::bind/function or std::bind/function anymore, it is just hugely more flexible if/when messages eventually need more than the simple stuff.

Share this post


Link to post
Share on other sites

You store a std::function in a map? And how do you get the different parameters in the callback method? Do you cast it in the method?

 

Lg

Dominik

 

Nope, it works out the same as what you have already.  You replace the explicit call of:

 

template< class T, class N, class MessageT >
    void subscribe(*instance, void(N::*memFunc)(const MessageT&))

with

template< class MessageT >

    void subscribestd::function< void (const MessageT&) func )

 

Basically doing all the same things but now you can use non-members, members, composites and all sorts of other variations of functions to connect your events with different systems.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this