[C++] Polymorphism - Derived Class Methods

Started by
11 comments, last by John Matrix 16 years, 1 month ago
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?
Advertisement
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?

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;}
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.
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?
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!
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?
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.
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.
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?

This topic is closed to new replies.

Advertisement