Skip to main content
GameDev.net gamedev.net
🔒 Locked

Using my V-Table

Started by Tim Cowley Jul 4, 2004 at 8:36 PM 14 replies 2.4k views
Original Post
Tim Cowley
Tim Cowley
I want to use it to automatically route messages to their correct handlers, but I have no idea how. Here's the source:
class EventHandler
{
public:
	void HandleEvent(Event * event)
	{
		//I want the event to go to the correct handler, or the default if none else is available.
		CheckEvent(event);
	}
	void CheckEvent(Event * event)
	{
		printf("Event/CheckEvent(%s)\n",event->GetName());
	}

	void CheckEvent(MouseClick * event)
	{
		printf("MouseClick/CheckEvent(%s)\n",event->GetName());
	}

	void CheckEvent(KeyDown * event)
	{
		printf("KeyDown/CheckEvent(%s)\n",event->GetName());
	}
};
I get the feeling I'm missing something really obvious here. I remember seeing a thread a while back on this topic, but with search disabled it would be somewhat difficult to track it down. Any ideas?
C-Junkie
C-Junkie
WEll, you just need to switch() on some type field in the Event structure, and call the appropriate handler.
Tim Cowley
Tim Cowley
That's precisely what I'm trying to avoid.
C-Junkie
C-Junkie
Unless you can change the event structure, it's not avoidable.

The switch() is fast, if that's what you're worried about, but it looks like it's only in this one place, so it's not like you're littering your code with switches..
Anon Mike
Anon Mike
Put CheckEvent in the Event object instead of EventHandler then you can just do event->CheckEvent.
-Mike
Tim Cowley
Tim Cowley
Quote:
Original post by C-Junkie
Unless you can change the event structure, it's not avoidable.

The switch() is fast, if that's what you're worried about, but it looks like it's only in this one place, so it's not like you're littering your code with switches..

If I was going for speed, I'd use a lookup table. I'm going for elegance :)

Quote:
Put CheckEvent in the Event object instead of EventHandler then you can just do event->CheckEvent.

I plan on having derived EventHandlers too ;)

EDIT: Where the fuck are my smileys? :
EDIT: V-Table is the wrong term to use. Essentially, I want to get RTTI working behind the scenes.
Tim Cowley
Tim Cowley
Beautiful. Thanks a lot :D
Fruny
Fruny
Also see the Visitor Pattern.

class EventHandler;class Event{public:  virtual ~Event() {}  virtual void Accept(EventHandler* eh);  const std::string GetName() { return typeid(*this).name(); }};class MouseClick : public Event {public:  virtual void Accept(EventHandler* eh);};class KeyDown : public Event {public:  virtual void Accept(EventHandler* eh);};class EventHandler{public:  void Visit(Event * event) { event->Accept(this); }  void Handle(Event * event)  {    std::cout << "Event/CheckEvent" << event->GetName() << std::endl;  }  void Handle(MouseClick * event)  {    std::cout << "MouseClick/CheckEvent" << event->GetName() << std::endl;  }  void Handle(KeyDown * event)  {    std::cout << "Keydown/CheckEvent" << event->GetName() << std::endl;  }};void Event::Accept(EventHandler* eh) { eh->Handle(this); }void MouseClick::Accept(EventHandler* eh) { eh->Handle(this); }void KeyDown::Accept(EventHandler* eh) { eh->Handle(this); }int main(int argc, char* argv[]){  EventHandler eh;  MouseClick m;  eh.Visit(&m);  return 0;}
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Tim Cowley
Tim Cowley
OK, I've run into problems. Thing is, I want both Events and EventHandlers to be virtual. And neither base class can know anything about its children. The visitor pattern doesn't cover this situation.
stay in school
stay in school
Just write one CheckEvent() method that takes an Event* as a parameter. Then make Event::GetName() virtual, and implement it in each subclass of Event. At runtime, the CheckEvent() function will know which version of GetName() to call from the vtable - no switch statements needed.
antareus
antareus
I have dealt with this problem before, and solved it at compile time mostly.

Event.hpp - base Event class templated on the derived event type

ContactEvents.hpp - sample of how you define events

Contact.cpp - sample of how you raise events (look at Contact::Update())

ProfileComponent.cpp - shows how to attach and detach from events, as well as how the event comes in
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
Zahlman
Zahlman
Quote:
Original post by Tim Cowley
OK, I've run into problems. Thing is, I want both Events and EventHandlers to be virtual. And neither base class can know anything about its children. The visitor pattern doesn't cover this situation.


... so you're dispatching on both the Event and the EventHandler.

... Take another look at the Double Dispatch page. :s
Tim Cowley
Tim Cowley
Quote:
Original post by antareus
I have dealt with this problem before, and solved it at compile time mostly.

Event.hpp - base Event class templated on the derived event type

ContactEvents.hpp - sample of how you define events

Contact.cpp - sample of how you raise events (look at Contact::Update())

ProfileComponent.cpp - shows how to attach and detach from events, as well as how the event comes in

Quote:
.../// Member function template support is necessary to use member function connections. I have
/// no interest in supporting poor attempts at compilers. (MSVC 6) If you still use
/// MSVC6, use free functions that then invoke the appropriate method on the component...

I got to this bit and stopped reading. I'm still stuck with VC6 :p Thanks anyway.

Quote:
... so you're dispatching on both the Event and the EventHandler.

... Take another look at the Double Dispatch page. :s

Yeah, but my problem is that each EventHandler would have to know about every possible Event. I don't want that :\ Here's what I want to do:

class Eventclass KeyDown : public Eventclass MouseClick : public Eventclass EventHandler{public:	void HandleEvent(Event * event);};class MenuEventHandler : public EventHandler{public:	void HandleEvent(Event * event);	void HandleEvent(MouseClick * event);};class GameEventHandler : public EventHandler{public:	void HandleEvent(Event * event);	void HandleEvent(KeyDown * event);};


I want to be able - using only an unknown Event pointer and an unknown EventHandler pointer - to call EventHandler::HandleEvent(Event *) and have it route down to the correct function. If there is no specific function defined for that event, it should be handled by the default HandleEvent(Event *) function provided by the derived class. After reading through all that wiki stuff, I'm starting to get the feeling this is impossible :(
C-Junkie
C-Junkie
Put virtual HandleEvents for all types into the Handler, and create a virtual HandeEvent in the event.

PointerToUnknownEvent->HandleEvent(PointerToUnkownHandler);

which calls (for instance) MouseEvent's HandleEvent (virtual call), which then

PointerToUnknownHandler->HandleMouseEvent(this);

tadaa.
antareus
antareus
It is not impossible.

Dig up the Gang of Four book - there is extensive discussion on this point. The gist of it is that you define a third EventVisitor to operate on the hierarchy without it knowing about it.

However I'd encourage you to instead do something like what I did:
a. write/use a functor class
b. write some sort of event propagation system that calls functors for specific events
c. construct event objects and trigger them when necessary

I think its more readable than a Visitor implementation is.

Oh and get that VC++ 2003 toolkit, no excuse to use VC6 nowadays. :)
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis

Topic Locked

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

Sign in to reply to this topic.