Event/Message ID

Started by
5 comments, last by Ahnfelt 15 years, 8 months ago
I'm having problems deciding what would be the best way to deal with event id's in my system. I want to avoid a big single enum for obvious reasons. Defining the ID by hand is error prone. As simple strings would bring to much overhead what i'm leaning to now is using an integer hash from the event name. But i want to avoid having the hash recomputed all the time so this is my thought:

typedef Hash EventID;

class Event
{
public:
	virtual const EventID & getEventID() const = 0;
};

class SomeEvent : public Event
{
public:
	static EventID ID;
	virtual const EventID & getEventID() const { return ID; }
};

// Implementation
EventID SomeEvent::ID("SomeEvent");


Is this a good way, is there any better? PS I don't want to use something like boost::bind to implement synchronous events, ie signals.
Advertisement
There's no need for virtuals.

class Event {public:  Event(const EventID & id)    : id(name)  {}private:  EventID id;};class EventID {public:  EventID(const char * name)    : hash(calculateHash)  {}  EventID(const EventID & other)    : hash(other.hash)  {}  // copy operatorprivate:  int hash;};

Then:
class MyCustomMessage : public Event {public:  MyCustomMessage()    : Event(ID)  {}  static EventID ID;};// ----EventID MyCustomMessage::ID("MyCustomMessage");
It really depends on what your ID is used for - maybe you can share a few use cases?

It seems to me like you're using it as the "type" of the event. In that case are you going to use downcasts after checking the type?
Quote:Original post by Antheus
There's no need for virtuals.

That depends if you want to add the id member to every object or not. But good point.

Quote:Original post by Ahnfelt
In that case are you going to use downcasts after checking the type? If so, there are object oriented / statically typed ways of solving this that you might want to look into.

Yes, it would be used as a type for casts. This would probably be done in the backend using thunks rather than user code though.
But i'm interested in the other ways. Please share.

Quote:Original post by lexs
Quote:Original post by Ahnfelt
In that case are you going to use downcasts after checking the type? If so, there are object oriented / statically typed ways of solving this that you might want to look into.

Yes, it would be used as a type for casts. This would probably be done in the backend using thunks rather than user code though.
But i'm interested in the other ways. Please share.


Polymorphism is the obvious alternative. You'd have to share a little more about exactly what you're trying to accomplish before anyone could give you specific advice.

If you're sending these events from one subsystem to another, perhaps one option is the Command pattern, where the receiving subsystem could call command->execute(this), which would call the appropriate methods on the subsystem.

Or if these events are broadcast, blend in the Visitor pattern and have executeAudio, executePhysics, executeRenderer, etc. So if you have a GrenadeExplosionEvent, it could define exactly how it affects each subsystem.

But I have no idea if this is relevant to what you're using "events" for.
Quote:Original post by drakostar
You'd have to share a little more about exactly what you're trying to accomplish before anyone could give you specific advice.


The events will basically be send from one subsystem to (several) others. When you send the event you won't specify an explicit receiver as all subsystems can register which events they care about. So the type/id will be used by the receiving subsystem to see which event it has received.

You can say that the subsystems have a update() function where they poll for received events instead of something like onEvent().

The events should only feature data and not know anything about which systems that may receive it.
I'm going to assume you're broadcasting:

class EventVisitor{    public:    virtual void visit(MouseClickEvent& event) {}    virtual void visit(KeyDownEvent& event) {}    virtual void visit(AwsomeEvent& event) {}};class Event{    public:    virtual void accept(EventVisitor& visitor) = 0;};class MouseClickEvent{    public:    virtual void accept(EventVisitor& visitor) { visitor.visit(*this); }};// Etc. for other event classes// And then for each place you need to handle events, you define a visitorclass SomeEventVisitor: public EventVisitor{    virtual void visit(MouseClickEvent& event) { /* handle this event */ }    virtual void visit(KeyDownEvent& event) { /* handle that event */ }};// And to invoke the event visitor / handlerSomeEventVisitor visitor;event.accept(visitor);


(but maybe I'm just starting to see the visitor pattern as the hammer and all problems as nails...)

EDIT: Note that the downside of this is that you need a central class (the EventVisitor) that enumerates all your event classes.

[Edited by - Ahnfelt on August 3, 2008 3:30:08 AM]

This topic is closed to new replies.

Advertisement