In file included from main.cpp:2:
./player.h:8:14: error: unknown type name 'Enemy'
void shoot(Enemy &Obj);
^
1 error generated.
In file included from player.cpp:2:
./player.h:8:14: error: unknown type name 'Enemy'
void shoot(Enemy &Obj);
^
player.cpp:15:14: error: out-of-line definition of 'shoot' does not match any
declaration in 'Player'
void Player::shoot(Enemy &Obj)
^~~~~
2 errors generated.
There needs to be, at minimum, a forward-declaration of Enemy before you try and use it in the declaration of your shoot member function. Alternatively, you can #include your enemy header in your player header.
class Player
{
public:
Player();
void shoot(Enemy &Obj);
private:
int health;
int armour;
};
class Enemy
{
public:
Enemy();
void displayhealth();
int gethealth();
int sethealth(int amount);
private:
int health;
int armour;
};
Looking at the code, consider the fact that both Player and Enemy have the same health and armor members. This suggests you are going to be repeating code in both of these classes.
Whenever you find yourself repeating code representing a common concept, a class is hinting it should be there, but it isn't (yet).
There are many possible ways to think of this. The 'classic' approach is to fashion a common base (perhaps character) which holds health and armor. The Player and Enemy would then inherit from "character", at which point the both have health and armor, but you're writing that only once instead of twice. This is not just the two variables, but all the functions which operate them that you are no longer duplicating.
Another, less common, is to fashion a class representing the common elements, and make that a member of both Player and Enemy. This skips virtual functions, but it is more appropriate when you can answer the basic question:
does this concept represent an "is-a" or "has-a" relationship.
If "health" and "armor" are attributes which define what a thing is, then the answer is "is-a".
If those represent something a thing possesses, then it is "has-a".
The "is-a" suggests inheritance, where has "has-a" suggests a member (that it owns).
@Albratross - I think I have already included the enemy.h header to player.cpp already?
@Niccole - Yes I see where you are getting at with writing multiple health and armour variables for the the player and enemy class. To determine what I should do. Shouldn’t Player and Enemy be "has a" health and armour? So should I make the Enemy class inherit the Player class? Player : Enemy?
In player.cpp, yes, but not player.h, despite you using Enemy inside player.h. See the problem?
@Niccolo makes an important point about when it's best for B to inherit from A: when B is (intuitively) a kind of A. Examples:
* A Tabby is a kind of Cat, so Tabby would inherit from Cat.
* A Cat is a kind of Animal
* A Walrus is also a kind of Animal, but not a kind of Cat.
And so on. This can actually get quite complicated when multiple inheritance comes into the picture, but we'll leave that be for now.
Is a Player a kind of Enemy? That doesn't really make sense, nor is an Enemy a kind of Player.
However, both of them are combatants. They both have health and armor, and they both participate in combat. So, if you were to make a third class called Combatant, it would be appropriate for Enemy and Player to inherit from Combatant.
I do prefer @Albatross' answer here, to inherit from a "Combatant" base. A Combatant's health is fairly described as an inherent property of what the Combatant is.
However, to explore the alternative is at least a functional exercise.
In some game engines you find a very common pattern to attach attributes to an object. The basic object is a position (often called a transform, the position and orientation - or angles). This basic object could be nothing else but this point in space. It might not even have a visible object representing it, which is a kind of special use case.
Most often, though, this basic object, a transform, is then given the attachment of a visible model (artwork). There may also be attached to this basic object some physical attributes, like mass and a collision shape. It can now react to gravity and force. It can be knocked around, roll, fall, etc.
Now, one might think that an object is a mass at a location. It is certainly a reasonable way to look upon an object. However, even if one thinks so, the game engines generally apply this physics attribute as a possession, so that it can be optional. Walls, for example, do not need mass, nor do they need to react to gravity (we set aside the possibility of wall destruction in this case). This saves processing time. There is, therefore, an alternative reason for making the physics values a possession rather than an inherited value (and related logic).
If you were to consider making health a possession, is it reasonable to think you might have a character that does not need a health value? I don't sense so.
On the other hand, armor could be missing. It may be something earned. It is, after all, likely a garment. Something possessed.
It is not unreasonable to debate these points with various perspectives, and to look for reasons.
One curious point to keep in mind is that if health and armor are unified into a class, these two very different subjects are tied together without reason. What does armor have to do with health? I realize armor protects the health, but are they directly associated? If not, perhaps this hints at something deeper about design.
For a trivial exercise, it may be just fine to put armor and health in a base class as an "is-a" relationship, for the convenience of C++ writing. They may be nothing more than integers with a few functions to control them. Hardly worth their own classes.
On the other hand, if armor begins to take on deeper meaning, it might eventually be separated. Perhaps in the future armor has artwork, something the character wears optionally. They might trade the armor in for better armor later. Armor could grow into its own, more complex implementation, leaving health as a mere value.
This, too, is part of the evolution of design you'll observe as you advance.