Sign in to follow this  
jamesleighe

Inheritance Issue

Recommended Posts

It's probably easier to explain with code...
How can I get something like this to compile? It says Player is abstract! (but the method that InputEventHandler requires has been implemented by a class I inherited)

The simplest case that illustrates my issue, the following code will not compile because InputEventHandler can't find the implementation of GetId even though it (should) be there because I inherited Entity.
[code]
class InputEventHandler
{
public:
virtual int GetId () = 0;
};

class Entity
{
public:
int GetId ()
{
return 23;
}
};

class Player: public Entity, public InputEventHandler
{

};

int main ()
{
Player* player = new Player;
delete player;

return 0;
}
[/code]

Thanks as usual!

EDIT: This is in C++

Share this post


Link to post
Share on other sites
I think InputEventHandler needs to be inherited by the provider of GetId() or one of its subclasses. In your case, Player inherits Entity, and Player inherits InputEventHandler, but Entity (which provides GetId()) doesn't inherit from InputEventHandler. So you either need to provide a Getid() in Player, or inherit InputEventHandler in Entity, or figure some other way to provide a GetId() in a class which inherits Entity.

Share this post


Link to post
Share on other sites
It's gona be too bad if you can't do stuff like this in c++, I'm not sure how to design around it (elegantly).

Can anyone say for certain that nothing like this is possible?

Share this post


Link to post
Share on other sites
Either:[code]class Entity : public InputEventHandler[/code]Or:[code]class Player: public Entity, public InputEventHandler
{
int GetId () { return Entity::GetId() };
};[/code]Or:[code]class Entity : public virtual InputEventHandler
...
class Player: public virtual InputEventHandler, public Entity
...[/code]This is a very strange design though; maybe we can give better advice if you explain the problem it's trying to solve?

Share this post


Link to post
Share on other sites
Here is the issue then:

All entities have a global unique ID, and that is implemented in a class called 'BaseEntity'. This 'UID' is used for various reasons and everything works peachy until I try to inherit IInputEventHandler from Player (which also inherits from BaseEntity) to get input signals.

That's pretty much it. It's kind of ugly to inherit IInputEventHandler from BaseEntity since only Players will ever handle input (at least they are the only Entities to handle input). The other option seems to reimplement GetUID in every entity in the game, also not great.

I could go into more depth, tell me what you would like to know!

EDIT: IInputEventHandler is an interface class that lets you hook into the input system to receive input messages FYI
[code]
class IInputEventHandler
{
DEF_UNIQUEID_INTERFACE

public:
~IInputEventHandler () { }

virtual void KeyPressEvent (uint32 virtualKey, bool isDown) = 0;
virtual void MouseMoveEvent (int32 deltaX, int32 deltaY) = 0;
virtual void MouseClickEvent (MouseButton button, bool isDown) = 0;
};
[/code]

Then you could say (from inside Player) "InputAPI ()->AddInputEventHandler (this);" and be good to go, but not so much so far. Is this an odd thing to do?

Share this post


Link to post
Share on other sites
If I understand what you're saying, it sounds like you want your classes to inherit virtually from BaseEntity.

Share this post


Link to post
Share on other sites
If you want to do this via inheritance, then I'd go with my second option from earlier ([i][font="Courier New"]int Player::GetId () { return Entity::GetId() };[/font][/i]).

However, I'd personally recommend you make a separate class responsible for handling player input.[code]class PlayerInputEventHandler : public InputEventHandler
{
public:
PlayerInputEventHandler( Player& p ) : m_player(p) {}
int GetId () { return p.GetId(); }
private:
Player& m_player;
};
class Player : public Entity
{
public:
Player() : m_input(this) {}
private:
PlayerInputEventHandler m_input;
};[/code]

Share this post


Link to post
Share on other sites
Hodgman brings up a good point with the alternate design pattern which could avoid the whole issue. You could also create a PlayerController base class and then override that with a version that handles input from a human and another one that does AI

Share this post


Link to post
Share on other sites
[quote name='SiCrane' timestamp='1310605975' post='4835076']
If I understand what you're saying, it sounds like you want your classes to inherit virtually from BaseEntity.
[/quote]

I wish so much that would work, but as far as I know (EDIT: tested, doesn't work) it wont work since this isn't a diamond inheritance issue.

This doesn't seem like an evil hack to anyone else? (Not that I don't seriously appreciate the input however! Also I probably WILL go with this method evil or not.)
[code]
class Player: public Entity
{
public:
Player (): inputHack_(this) { }

void DoInput (int input) { }

private:
class InputHack: public InputEventHandler
{
public:
InputHack (Player* player): player_(player) { }

void DoInput (int input)
{
player_->DoInput (input);
}

int GetId ()
{
return player_->GetId ();
}

private:
Player* player_;
};

InputHack inputHack_;
};
[/code]

I'll just have to weigh my options here.

(important) EDIT: Now that I think about, it, having a class wrap over IInputEventHandler could be a good thing! I could use that to cleanly allow me to have configurable movement binds or somthing and maybe like detect double key-presses for special things like dodging and whatnot!

Share this post


Link to post
Share on other sites
I'd suggest against deep inheritance hierarchy, and consider composition. The whole idea of there being a BaseEntity and Entity, and all "entities" in a game inheriting from them, sounds like trouble to me.

[code]
class InputEventHandler;
class IdSource; // int GetId()

class Player
{
public:
Player(InputEventHandler* handler, IdSource* source)
: handler(handler), source(source)
{
}
InputEventHandler& Handler()
{
return *handler;
}
IdSource const& IdSource()
{
return *source;
}

private:
InputEventHandler* handler; // shared_ptr
IdSource* source; // shared_ptr
};
[/code]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this