When to use inheritance

I'm pretty new to object oriented stuff and have a tough time figuring out when to use inheritance. For instance suppose a simple graphical game has a class for each object on the screen. This class has, at the very least, a pointer to the object's sprite and x and y coordinates as members.
There will be certain objects that require additional members, like text and scores would require string fields, a ball that moves around might require a field for it's direction of travel etc.

It seems as if it would be simpler to just create one class and overload the constructor to accept the arguments each object needs while setting the rest to null values. Is this normally the way stuff like this is done? Or is it more common to set up inheritance hierarchies? Please don't be too harsh- I don't have much experience with this.

There are 3 main relationships with classes:

1. "IS A" implies inheritance - the derived class "IS A " type of the base class. The base class is the more general and the derived is more specialised. So if the base had a, b variables and / or functions, and the derived had a, b, c, d then it might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class CBase {
protected:  //similar to private, but derived classes can access as well

int m_a;  //member variable with leading m_  - a good convention to use
int m_b;  //helps when there are function arguments

public:

int MyFunctionM();
int MyFunctionN();

};

class CDerived : public Base {
protected:

int m_c;
int m_d;

public:

int MyFunctionJ();
int MyFunctionK();

};


In this setup an object of CDerived class type has access to functions MyFunctionM, MyFunctionN, MyFunctionJ, MyFunctionK. These functions have access to all 4 of the variables. You cannot get at these from the object. Don't fall into the trap of providing get / set functions for each member variable.

An example of this might be a base class CShape, with derived classes CSquare, CCircle.

2. "HAS A " This where a class has a variable which is of the type of another class. Example class CCircle with a member variable m_Centre of type CPoint.

3. "USES A" This where an argument is of a class type.


Class design is more involved than it looks. You have to consider how they are all going to work together. Entire books have been written on the subject.

Sometimes it is good to create classes are not instantiated into an object, but they help with the inheritance. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class CFood {
double m_weight;
//nutritional values here

};

class CFruitVeg: public CFood {
private:
string m_Variety;
protected:
CFruitVeg(); //constructor protected - can't make an obj of this type
};

class CFruit : public CFruitVeg {
//members specific to fruit
};

class CVeg: public CFruitVeg {
//members specific to vegetables

};


The variable m_Variety is now available to fruit and vegetable objects. So the idea of this is to specify things only once by pushing variables / functions as high up the inheritance tree as you can.


Also read this:

http://www.cplusplus.com/doc/tutorial/


A much more advanced thing is design patterns:

http://www.vincehuston.org/dp/


Hope all goes well.
Last edited on
Thanks TheIdeasMan. Appreciate that quite a bit.. Yeah the tutorials on this site are pretty good...

I guess what I was asking was more of an opinion question...Whether, given the situation I described, there's any reason I should use inheritance rather than the other method I described. I apologize if it's a stupid question. :)

It seems as if it would be simpler to just create one class and overload the constructor to accept the arguments each object needs while setting the rest to null values. Is this normally the way stuff like this is done? Or is it more common to set up inheritance hierarchies?


Firstly I should admit that I have virtually no experience with game programming - I am just going on what I think might be logical.

Having one superclass for everything doesn't sound like a good idea IMO. An inheritance tree would need to be designed properly.

I can relate something that might give a bit of insight possibly. The situation is how to model Players, Enemies and Weapons.

With Weapons there lots of different types, but you can group them together based on properties they have in common - for example swords, daggers, knives etc; then there might spears, clubs, Crossbows, Bows. The model for this Would have a base class CWeapon , with the others in an inheritance tree going down from there. A common feature for all of them might be damage that can be inflicted on a player.

With Players & Enemies, they both move, can attack, receive damage, and possess & use weapons. So they might both have a base class called CActor.

As I said earlier, class design isn't necessarily easy - you have to think about how they are all going to interoperate. If you get the class design wrong then that will cause kinds of grief.

It is only worth using inheritance if it is going to help you.

The other thing is the concept of virtual functions. This allows the definition of a function high up in the inheritance tree, that is inherited to all the derived classes, but it may also be changed to reflect specialisation of a derived class. An example might be different Enemies that attack in slightly different ways. Or weapons that do different things.

The whole thing gets complex quickly - I am sorry I don't really have enough knowledge to help you, except I might be able to see if something doesn't make sense. But there are plenty of guys & girls who ought to know how to go about it in the first place.

Any way - really good luck !!!!!!
You have to be careful with inheritance. There's inheritance of interface and inheritance of implementation.

Inheritance of implementation is what you get when you do:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Rectangle
{
    int x, y, dx, dy;
public:
    virtual void setDimensions(int x, int y, int dx, int dy);
    virtual int getArea() const;
    virtual int getCircumfrence() const;
    virtual Color getColor() const;
    //...
};

class Square : public Rectangle
{
public:
    virtual void setDimensions(int x, int y, int dx, int dy);  // override, ensure dx==dy
    // we get all the other stuff for free, yay!
};


Inheritance of interface is what you get when you do:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class IScreenObject
{
|public:
    virtual void getPos(int &x, int &y) = 0;
    virtual Color getColor() const = 0;
    virtual void draw(IScreen &screen) = 0; 
};

class Ball : public IScreenObject
{
public:
    virtual void getPos(int &x, int &y);
    virtual Color getColor() const;
    virtual void draw(IWindow &screen); 
};


The two have different uses, and you multiply inherit interfaces safely. It sounds like you might want to inherit an interface rather than code.
In spite of the cautions by others about inheitance, the best way to learn about it is to try it and see how it works.

In your example, since every screen object has a pointer to a sprite in addition to x and y, then it makes sense to make that a base class and derive your other classes from it.

1
2
3
4
5
6
class CSprite
{  int x, y;
    void * p_sprite;  // better if this is an explicit type
public:
   // constructors & functions
};

This has the benefit of not having to repeat the variables and methods in every class.
1
2
3
4
class Square : public Rectangle
{
public:
    virtual void setDimensions(int x, int y, int dx, int dy);  // override, ensure dx==dy 
That's the Ur example of LSP violation
With Weapons there lots of different types, but you can group them together based on properties they have in common - for example swords, daggers, knives etc; then there might spears, clubs, Crossbows, Bows. The model for this Would have a base class CWeapon , with the others in an inheritance tree going down from there. A common feature for all of them might be damage that can be inflicted on a player.
Noting that the properties are changing, but not the behaviour, I would rather use prototypes than inheritance trees.

Another example. An enemy is an actor that has an AI. A player is an
actor that the user controls.
1
2
Actor player( new user_control() ); 
Actor enemy( new attack_on_sight() );



The point is, inheritance is a really coupling relationship, making hard
to change later. Don't abuse it.
Last edited on
@ne555

I wonder if you could indulge in educating me (& others, including the OP) a bit, in relation to these:

LSP violation


What does LSP mean?

Noting that the properties are changing, but not the behaviour, I would rather use prototypes than inheritance trees.


What is a quick example of a prototype as opposed to inheritance?

One thing I have trouble seeing, is not having an inheritance when the objects all have properties in common. If one has separate classes for each, then there is not only duplication of the properties (member variables), but also duplication of the class functions that operate with the properties. This is the reason for the use of inheritance and virtual or pure virtual functions - isn't it?

I also wonder that the complexity of these game situations leads to using design patterns like mediator to deal with these problems better. I think JLBorges (from memory) mentioned that to me a while back. Does the use of design patterns help with the coupling relationship you mentioned?

I guess this shows how tricky class design might be & pitfalls that might be encountered - I am just trying to get a better handle on some of these concepts.
Last edited on
https://en.wikipedia.org/wiki/Liskov_substitution_principle#A_typical_violation

Don't have enough experience or knowledge, If I'm wrong please correct.

For the prototypes. Suppose that you have a weapon class, and want a dagger, a sword, an axe and a bow.
I don't see difference between them, except in their state. So I would do
1
2
3
4
sword := Weapon attack: 14; fire_rate: 2; range: 2.
dagger := Weapon attack: 5; fire_rate: 1; range: 1.
axe := Weapon attack: 23; fire_rate: 4; range: 3.
bow := Weapon attack: 3; fire_rate: 7; range: 10.
Now if you want to create a sword you simply do my_weapon := sword.
This is more flexible than doing Weapon subclass: Sword as you could easily create more weapons without touching the source code.
Thanks for the in depth and thoughtful responses folks. This definitely gives me a lot to think about and is really much more information than I imagined I would get.

It'll probably take me a couple days to look over as some of this code is, to be honest, right on to just over the edge of my ability. Thanks again. :)
Last edited on
Topic archived. No new replies allowed.