Inheritance Issue

Started by
8 comments, last by Codarki 12 years, 9 months ago
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.

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;
}


Thanks as usual!

EDIT: This is in C++
Advertisement
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.
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?
Either:class Entity : public InputEventHandlerOr:class Player: public Entity, public InputEventHandler
{
int GetId () { return Entity::GetId() };
};
Or:class Entity : public virtual InputEventHandler
...
class Player: public virtual InputEventHandler, public Entity
...
This is a very strange design though; maybe we can give better advice if you explain the problem it's trying to solve?
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

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;
};


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?
If I understand what you're saying, it sounds like you want your classes to inherit virtually from BaseEntity.
If you want to do this via inheritance, then I'd go with my second option from earlier ([font="Courier New"]int Player::GetId () { return Entity::GetId() };[/font]).

However, I'd personally recommend you make a separate class responsible for handling player input.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;
};
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

If I understand what you're saying, it sounds like you want your classes to inherit virtually from BaseEntity.


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.)

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_;
};


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!
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.


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
};

This topic is closed to new replies.

Advertisement