Sign in to follow this  

[C++] Polymorphism - Derived Class Methods

This topic is 3571 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I understand the basic concepts of polymorphism but the tutorials that I have read don't seem to mention a bit of information I need. Say I have a base class:
class Player
{
	public:

	Player();
	~Player();

	void displayPlayer();	//Display the player
};

Then a derived class:
class Attacker : public Player
{
	public:
		
		Attacker();
		~Attacker();
		
		void checkPositionType();
};

When I create a new Attacker using a player pointer a la:
Player* attacker = new Attacker

I can call all the methods in the base class thus:
attacker->displayPlayer();

but I can't call the methods that are only in the derived class:
attacker->checkPositionType();

Now I beleive I can get around this by putting the 'checkPositionType()' function that is in the derived Attacker class in the base Player class as a virtual function so that it gets overwritten but is there a way I can avoid doing this and only have the function in the derived class yet still call it using a Player pointer?

Share this post


Link to post
Share on other sites
Does it make sense for you to get get the position type of a player?

If it does, then give the player class a getPositionType function.

If it doesn't, then don't call getPositionType on a pointer-to-a-player, precisely because it doesn't make sense.

After all, your pointer may well be pointing to a non-attacker object, at which point calling the function simply cannot work. Of course, if you know that the object you are handling is an attacker, then why do you have a pointer-to-a-player instead of a pointer-to-an-attacker?

Share this post


Link to post
Share on other sites
You've declared a pointer to a Player. At compile time, the compiler only knows the method names of the Player methods. Any child class methods are unavailable the way you've done it.

What I would do is define some sort of interface. Make an Actor class, a base class that both Player and Attacker inherit from. This class doesn't so anything itself, but it does define the interface that all objects of this type must implement. You can also put any code common to all of the types directly in this class.


class Actor {
public:
// Interface function
void draw() { draw_it(); }
virtual int get_hp() = 0; // This is "pure virtual," define it in child classes
};

class Player : public Actor {
public:
virtual int get_hp() { return max_hp - damage; }
};

class Attacker : public Actor {
public:
virtual int get_hp() { return hp_level[level] - damage; }
};



Now, you can do things like this:

bool is_dead( Actor* a ) {
// Return true if hp is less than 0
return a->get_hp() < 0;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Does it make sense for you to get get the position type of a player?

If it does, then give the player class a getPositionType function.

If it doesn't, then don't call getPositionType on a pointer-to-a-player, precisely because it doesn't make sense.

After all, your pointer may well be pointing to a non-attacker object, at which point calling the function simply cannot work. Of course, if you know that the object you are handling is an attacker, then why do you have a pointer-to-a-player instead of a pointer-to-an-attacker?


This where things could get complicated. I'm making a soccer game where I also have a defender class which is derived from the player class. I need to store a pointer to the player who has the ball which could be an Attacker or a Defender. So I need a pointer which can point to either a defender or an attacker.

Player* inPossession

Then depending on which type it points to (which I will have worked out) I need to call approriate functions which are specific to the type of class which is being pointed to.

So say an attacker was in possession I would call:

inPossession = Attacker1;

inPossession->shootForGoal();

Now a defender will not be shooting for goal so I only want this 'shootForGoal()' function to be in the Attacker class but I also want it to be accessed by the Player pointer.

Just noticed a reply while I was typing that. Monkey I'll have a look at your post in a second.

Share this post


Link to post
Share on other sites
Quote:
Original post by John Matrix
Then depending on which type it points to (which I will have worked out) I need to call approriate functions which are specific to the type of class which is being pointed to.


In short, you have a function which, depending on the type the pointer points to, will do different things. This is the textbook definition of a virtual function.

Which brings me to my next question: why do you make the effort, in that function, to determine the type of the object and then try to cast it back to the correct type in order to call its member functions, when you could wrap all that behavior into a single virtual function which needs no type-determination or type-casting to do its work?

Share this post


Link to post
Share on other sites
Quote:
Original post by UziMonkey
You've declared a pointer to a Player. At compile time, the compiler only knows the method names of the Player methods. Any child class methods are unavailable the way you've done it.

What I would do is define some sort of interface. Make an Actor class, a base class that both Player and Attacker inherit from. This class doesn't so anything itself, but it does define the interface that all objects of this type must implement. You can also put any code common to all of the types directly in this class.

*** Source Snippet Removed ***

Now, you can do things like this:
*** Source Snippet Removed ***


Ok, that looks like a better solution than having all the attacker functions as virtual functions in the player class. It's still a compromise, but a better one than mine I think. Thanks!

Share this post


Link to post
Share on other sites
Quote:
Original post by John Matrix

Now I beleive I can get around this by putting the 'checkPositionType()' function that is in the derived Attacker class in the base Player class as a virtual function so that it gets overwritten but is there a way I can avoid doing this and only have the function in the derived class yet still call it using a Player pointer?


Yes you can cast the player pointer to an attacker with dynamic_cast. Directly with out the cast no, as well you shouldn't be able to. Think of this situation
class A{functionA()}
class B : public A{ functionB()}
class C : pubilc A{functionC()}
now if you have
A* stuff;
if(something)
stuff= new C;
else
stuff = new B;

Should stuff have access to all of B's and C's functions, of course not all you know is you have something that can behave like an A. If you run into the situation where you need to do the cast you are more than likely doing something wrong.

Edit wow a lot can happen in a few min. why not have a handle ball near goal function that makes attackers shoot and defenders do what ever they need to do?

Share this post


Link to post
Share on other sites
Quote:
Original post by stonemetal
Yes you can cast the player pointer to an attacker with dynamic_cast.


dynamic_cast is warranted only in very specific cases, such as parallel inheritance trees. Most of the time, cleaning up the design by making virtual the functions that need to be virtual will result in a working system without dynamic casting.

In this case, it certainly looks like it would work without dynamic casting.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
Original post by John Matrix
Then depending on which type it points to (which I will have worked out) I need to call approriate functions which are specific to the type of class which is being pointed to.


In short, you have a function which, depending on the type the pointer points to, will do different things. This is the textbook definition of a virtual function.

Which brings me to my next question: why do you make the effort, in that function, to determine the type of the object and then try to cast it back to the correct type in order to call its member functions, when you could wrap all that behavior into a single virtual function which needs no type-determination or type-casting to do its work?


But I don't think these are functions which depending on the type the pointer points to will do different things. I'm dealing with functions that are specific to each derived class, that is a function that an attacker needs but a defender does not need.

It was my understanding that I would use a virtual function when the function in the base class is used in BOTH the derived classes. So a generic function like 'updatePlayer()' is needed in both the attacker AND the defender class so I make this virtual in the base class and overwrite it in each of the base classes.

But ONLY an attacker will make an action like 'shootToGoal()', a defender doesn't need this function as it is only concerned with preventing a shot. So to include it in the base class as a virtual function would be useless as the defender doesn't need it. I hope I understood your question and I'm not barking up the wrong tree here.

Share this post


Link to post
Share on other sites
Quote:
Original post by John Matrix

But I don't think these are functions which depending on the type the pointer points to will do different things. I'm dealing with functions that are specific to each derived class, that is a function that an attacker needs but a defender does not need.

It was my understanding that I would use a virtual function when the function in the base class is used in BOTH the derived classes. So a generic function like 'updatePlayer()' is needed in both the attacker AND the defender class so I make this virtual in the base class and overwrite it in each of the base classes.

Yes you are correct.
Quote:

But ONLY an attacker will make an action like 'shootToGoal()', a defender doesn't need this function as it is only concerned with preventing a shot. So to include it in the base class as a virtual function would be useless as the defender doesn't need it. I hope I understood your question and I'm not barking up the wrong tree here.


Yes but you can call shoot ToGoal in the over written UpdatePlayer because after you have made the polymorphic function call you are in the derived class and can access anything you need.

I take that back it sounds like all of the code that belongs to a player isn't in the player class. why is something trying to force the player to shoot the ball?

Share this post


Link to post
Share on other sites
Quote:
Original post by John Matrix
I hope I understood your question and I'm not barking up the wrong tree here.


You didn't understand, so I'll try to clarify. Somewhere in your code, you have a function which looks like this:
void handle_possessor()
{
Player *handled = inPossession;

if (is_of_type(handled, ATTACKER))
{
handled -> checkPositionType();
handled -> doSomeAttackerThings();
}

else if (is_of_type(handled, DEFENDER))
{
handled -> doSomeDefenderThings();
}

else assert(false); // Don't know what to do
}


Of course, the actual function calls don't work, because you're using a wrong pointer type. However, the function handle_possessor needs to do different things depending on whether the possess or is an attacker or a defender. As such, it should be a virtual function:

class Player
{
// ...
virtual void handle_possessor() = 0;
};

class Attacker
{
// ...
void handle_possessor()
{
checkPositionType();
doSomeAttackerThings();
}
};

class Defender
{
// ...
void handle_possessor()
{
doSomeDefenderThings();
}
};

void handle_possessor()
{
Player *handled = inPossession;
handled -> handle_possessor ();
}


This has the advantage of eliminating type-checks and type-casts, while making sense: after all, you need to handle the ball possessor regardless of what player type it actually is (thus making it a function in the Player class is warranted), and every player type reacts differently (so you can make it a virtual function and override it in derived classes).

Share this post


Link to post
Share on other sites
Quote:
Original post by stonemetal
Yes but you can call shoot ToGoal in the over written UpdatePlayer because after you have made the polymorphic function call you are in the derived class and can access anything you need.


Ok that's handy for future reference, but I don't think the way I have designed my program at the moment will let me do that.

Quote:
It rather sounds like you are employing "The Bag" anti design pattern. Why not separate it out so that you have a list of attackers and a list of defenders.


I did have a list of each but the way I have the program designed just now I do need the 'inPossession' pointer to point to either an Attacker or a Defender. I might be able to change that if (as it seems) it's a lot of trouble to have it do so.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
Original post by John Matrix
I hope I understood your question and I'm not barking up the wrong tree here.


You didn't understand, so I'll try to clarify. Somewhere in your code, you have a function which looks like this:*** Source Snippet Removed ***

Of course, the actual function calls don't work, because you're using a wrong pointer type. However, the function handle_possessor needs to do different things depending on whether the possess or is an attacker or a defender. As such, it should be a virtual function:*** Source Snippet Removed ***

This has the advantage of eliminating type-checks and type-casts, while making sense: after all, you need to handle the ball possessor regardless of what player type it actually is (thus making it a function in the Player class is warranted), and every player type reacts differently (so you can make it a virtual function and override it in derived classes).


Ok that definetely makes sense! I'm still not sure if I can do it like this though because of how I've made the program so far but I'll have a look and see if I can manage it after a bit of code mangling.

This isn't really important in the grand scheme of my program so I might just go with a quick fix for now, but all your posts will be helpful in future.

Share this post


Link to post
Share on other sites

This topic is 3571 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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