Basic polymorphism/event receiver

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Moo
Posts: 30
Joined: Fri Jan 09, 2009 10:07 pm

Basic polymorphism/event receiver

Post by Moo »

Hi :) I've tried to make a simple event receiver class to experience how the whole Irrlicht OOP system worked and to practice polymorphism. (this being my reacher). The whole thing compiles fine and I thought I had understood it all, but I get

Code: Select all

Unhandled exception at 0x1010af46 in Client.exe: 0xC0000005: Access violation reading location 0x00000004.
At runtime. Here is my code:

Event.h

Code: Select all

#include "Global.h"
#include <iostream>

class CGameEventReceiver : public IEventReceiver
{
	private:
		IrrlichtDevice* Device;
	public:
		CGameEventReceiver(IrrlichtDevice* device);
		virtual bool OnEvent(const SEvent& event);
};

IEventReceiver* createGameEventReceiver(IrrlichtDevice* device);
Event.cpp

Code: Select all

#include "Event.h"

bool CGameEventReceiver::OnEvent(const SEvent &event)
{
	if (event.EventType == EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
	{
		switch (event.KeyInput.Key)
		{
			case KEY_ESCAPE:
				Device->closeDevice();
			default:
				break;
		}
	}
	return false;
}

CGameEventReceiver::CGameEventReceiver(IrrlichtDevice* device)
{
	Device = device;
}

IEventReceiver* createGameEventReceiver(IrrlichtDevice* device)
{
	CGameEventReceiver er(device);
	return &er;
}
Main.cpp (calling it)

Code: Select all


	IEventReceiver* er = createGameEventReceiver(Device);
	Device->setEventReceiver(er);
Thanks and sorry for not knowing how to use a debugger :(
rogerborg wrote:Answering a noob question is like having sex with a midget: there's a wonderfully satisfying sensation of being a giant.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

this is bad:

Code: Select all

IEventReceiver* createGameEventReceiver(IrrlichtDevice* device)
{
   CGameEventReceiver er(device);
   return &er;
} 
you're creating an event receiver (er) and return a pointer to it, but after the function returns to main er is no longer existant, because it's only local and so only existant inside this function !!! ;)

you could define er as a global, probably not wanted...

or you can do it this way:

Code: Select all

IEventReceiver* createGameEventReceiver(IrrlichtDevice* device)
{
   CGameEventReceiver* er = new CGameEventReceiver(device);
   return er;
} 
but than you'll need to delete the returned pointer when it's no longer needed (usually at program end)...

or you can do it this way:

Code: Select all

IEventReceiver createGameEventReceiver(IrrlichtDevice* device)
{
   CGameEventReceiver er(device);
   return er;
} 
this way you return a copy of er and not a pointer to it... ;)

but I'm not sure why you create this function just for this one creation call ???
why not creating the event receiver directly instead of calling this function ??? :shock:
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Acki wrote: or you can do it this way:

Code: Select all

IEventReceiver createGameEventReceiver(IrrlichtDevice* device)
{
   CGameEventReceiver er(device);
   return er;
} 
This code is illegal and bad. It is illegal because you cannot instantiate an abstract class (you can't create an instance of IEventReceiver). It is bad because if this were legal, you'd be slicing the CGameReceiver object.

Travis
Moo
Posts: 30
Joined: Fri Jan 09, 2009 10:07 pm

Post by Moo »

Yeah, well I used the new keyword. So here is my class so far:

Code: Select all

class CGameEventReceiver : public IEventReceiver
{
	private:
		CEVENT_STATE mouseStates[2];
		CEVENT_STATE keyStates[KEY_KEY_CODES_COUNT];
		CPROCESS_STATE processState;
		CMouseData mouse;

		IrrlichtDevice* Device;
	public:
		CGameEventReceiver(IrrlichtDevice* device);
		virtual bool OnEvent(const SEvent& event);
		CEVENT_STATE getKeyState(EKEY_CODE key);
		CEVENT_STATE getMouseState(CMOUSE_BUTTON button);
};

IEventReceiver* createGameEventReceiver(IrrlichtDevice* device);
Now I'm struggling with an odd (but probably noobish) problem. When creating my event receiver:

Code: Select all

	IEventReceiver* er = createGameEventReceiver(Device);
	Device->setEventReceiver(er);
I can't use the functions specific to CGameEventReceiver with the IEventReceiver pointer because I'm using it as a base class. So I can use

Code: Select all

er->OnEvent
er->~IEventReceiver
Because they are virtual methods of the abstract base class IEventReceiver, but I can't use

Code: Select all

er->getKeyState
er->getMouseState
because I'm using the IEventReceiver pointer.

So question: How do I use the custom functions of a derived pointer of an instance of an abstract base class? My goal is to use

Code: Select all

er->getKeyState
er->getMouseState
Thanks, and sorry if I'm not clear. I know it's confusing but IDK how to put it clearly.
rogerborg wrote:Answering a noob question is like having sex with a midget: there's a wonderfully satisfying sensation of being a giant.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

vitek wrote:This code is illegal and bad.
so now I'll get arrested !?!?! :lol:
yeah, you're right, I had normal vars in mind... ;)

Moo wrote:So question: How do I use the custom functions of a derived pointer of an instance of an abstract base class? My goal is to use

Code: Select all

er->getKeyState
er->getMouseState
you probably mean "from a pointer to an instance of a derived class"... ;)

well, I think this is not what you want:

Code: Select all

IEventReceiver* createGameEventReceiver(IrrlichtDevice* device);
this will create/return the normal (standard) event receiver,

but as far as you want your custom event receiver you'll need this:

Code: Select all

CGameEventReceiver* createGameEventReceiver(IrrlichtDevice* device);
and of course this then:

Code: Select all

CGameEventReceiver* er = createGameEventReceiver(Device);
but if you create the custom receiver inside the function and just returning a pointer to the standard receiver, then you also can try a cast like this:

Code: Select all

((CGameEventReceiver*)er)->getKeyState
Last edited by Acki on Thu Feb 26, 2009 1:22 am, edited 2 times in total.
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
Moo
Posts: 30
Joined: Fri Jan 09, 2009 10:07 pm

Post by Moo »

Surprisingly, the hackish cast seems to work. Any depreciation on thiscode? Any reason why I shouldn't use it? :P Looks too good to be true
rogerborg wrote:Answering a noob question is like having sex with a midget: there's a wonderfully satisfying sensation of being a giant.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

Moo wrote:Surprisingly, the hackish cast seems to work.
it's not surprisingly and not hackish, sometimes you'll have no other choice than doing such a cast... ;)
Moo wrote:Any reason why I shouldn't use it?
no, not in this case...
maybe if you do such a cast inside your main loop, because of performance reasons...
I did no benchmark tests, but I can imagine that such a cast is a bit more expensive than using the correct type directly...
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
Moo
Posts: 30
Joined: Fri Jan 09, 2009 10:07 pm

Post by Moo »

Acki wrote:
Moo wrote:Surprisingly, the hackish cast seems to work.
it's not surprisingly and not hackish, sometimes you'll have no other choice than doing such a cast... ;)
Moo wrote:Any reason why I shouldn't use it?
no, not in this case...
maybe if you do such a cast inside your main loop, because of performance reasons...
I did no benchmark tests, but I can imagine that such a cast is a bit more expensive than using the correct type directly...
The whole thing is about using it in the main loop. But maybe I could make it typecast only if an event occurs. But I don't know which parameter to use for the OnEvent bool. Example:

Code: Select all


	while(Device->run())
	{
		if(er->OnEvent(----------))
		{
			if(((CGameEventReceiver*)er)->getKeyState(KEY_ESCAPE) == RELEASED)
			{
				Device->closeDevice();
			}
		}
	}
Thanks again :)
rogerborg wrote:Answering a noob question is like having sex with a midget: there's a wonderfully satisfying sensation of being a giant.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

no, you shouldn't call onEvent on your own, it's a callback for events that occures and uses an event as parameter...
I think there is no other way then doing the type cast, beside using the correct type directly...
you could add a flag that specifies if an event has happened, but inside the receiver it would cause the same type cast...
or make this flag global, that would be a workaround...

but I would use the correct type everywhere (changing all the IEventReceiver* to CGameEventReceiver*), it would be much more effective in this case... ;)
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
Post Reply