Jump to content
  • Advertisement
Sign in to follow this  
Dominik2000

Message system problem

This topic is 1730 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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
Advertisement
Guest Hiwas

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

Edited by Dominik2000

Share this post


Link to post
Share on other sites
Guest Hiwas

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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!