Skip to main content
gamedev.net
🔒 Locked

Visitor pattern, double despatching

Started by ph33r 6 replies 750+ views
Original Post
ph33r
ph33r
Those words scare me but that is what someone mentioned I need to use. EntityManager ------------- vector(Entity*) entitieList; void Send( int ENTID, enum MESSAGE, void* param1, void* param2 ); Entity ------ virtual Recieve( int ENTID, enum MESSAGE, void* param1, void* param2 ); Every object in the game is registered in the entity manager, and every object is derived from an Entity. When one object wants to send a message to another, it calls EntityManager::Send( id, message, param1, param2 ), The entity manager calls recieve on the entity and hat object it is calling needs to catch the message(or discard it). This is all fine an dandy but I'm using void* and c-style casts all over the place. I'd like to move this to template parameters and so every recieve function for each object in the game could have their own proper types. Someone said I need to use double despatching and the visitors pattern but left it at that and I have no idea where to start. [edited by - ph33r on June 8, 2004 2:41:40 PM]
the Speed Bump
the Speed Bump
quote:
I'm using void*
Don't do that.
quote:
and c-style casts all over the place.
Don't do that either. C++ casts are ugly in the hopes that it will make you not want to use casts. (it's a shame that C-style casts are still legal C++)
quote:
I'd like to move this to template parameters and so every recieve function for each object in the game could have their own proper types.
Templates are a fantastic solution to a lot of problems. This isn't one of those problems.
quote:
Someone said I need to use double despatching and the visitors pattern but left it at that and I have no idea where to start.
Visitor is a great solution to a problem that's completely different from yours.

It sounds like you've already done most of the hard work. All you need to do is make sure that your Entity::Receive method is virtual. (ideally, pure virtual) ent->Receive(...) will then call the correct method for whatever type a given entity happens to be.

"Without deviation, progress itself is impossible." -- Frank Zappa

[edited by - the speed bump on June 9, 2004 3:28:21 AM]
"There is only one everything"
PeterTarkus
PeterTarkus
quote:
Original post by the Speed Bump
C++ casts are ugly in the hopes that it will make you not want to use casts. (it''s a shame that C-style casts are still legal C++)



What kind of dumb advice is that? Oh, you''re from Canada.
MadKeithV
MadKeithV
quote:
Original post by PeterTarkus
What kind of dumb advice is that? Oh, you''re from Canada.


It''s not advice, the first half is fact and the second is opinion (and an opinion I share). I''m sure you''ve noticed the warning. Don''t post flamebait replies that don''t add any useful information to the topic.

It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
antareus
antareus
I ran into a similar problem with my event system.

Event.hpp
You''ll want to browse around to see how I did it, but I basically used type erasure to avoid vtable bloat.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
ph33r
ph33r
That code is great antareus, but I have no idea what it does.

The Speed Bump: I''m confused are you saying that Entity::Recieve prototype should look exactly like this?


class Entity
{
public:
// note the use of the elipse operator

virtual Recieve(...) = 0;
};


Then any derived class can put any types in there and any amount of arguements, and it will work correctly?

the Speed Bump
the Speed Bump
quote:

class Entity
{
public:
// note the use of the elipse operator
virtual Recieve(...) = 0;
};


Then any derived class can put any types in there and any amount of arguements, and it will work correctly?


errrr no. I think I misunderstood your problem. Sorry about that.

If you want to be able to safely pass different parameters around for different messages, then Visitor is exactly what you need.

The basic idea is that the message to be consumed knows what it is, so it follows that it is able to send itself to a consumer. The consumer, then, can respond to an unknown message by sending it to itself.

struct Entity {
virtual void recieve(EntityMessage* msg) {
msg->visit(this);
}

virtual void recieveMoveMessage(MoveMessage* m) = 0;
virtual void recieveStopMessage(StopMessage* m) = 0;
};

struct EntityMessage {
virtual void visit(Entity* ent) = 0;
};

struct MoveMessage : EntityMessage {
virtual void visit(Entity* ent) {
ent->recieveMoveMessage(this);
}
};

struct StopMessage : EntityMessage {
virtual void visit(Entity* ent) {
ent->recieveStopMessage(this);
}
};


"Without deviation, progress itself is impossible." -- Frank Zappa
"There is only one everything"

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.