When we start implementing more complex systems using classes, we quickly encounter a problem. We'll have multiple types of objects that have a lot of similar requirements. However, they're not so similar that we'd want them to both share the exact same class.
For example, lets imagine a future where we are trying to create three types of objects: rocks, goblins and dragons.
The Rocks just need one ability:
The Goblins need these abilities:
The Dragons need these abilities:
Trying to model these as a single class is problematic. The class would be very complex. Additionally, most of our objects would be carrying around a lot of variables they will never use.
The ability to move would require variables to control things like movement speed. Having every rock carry around those variable seems like a waste of memory.
Equally, trying to create three totally separate classes for these objects isn't ideal. We'd end up having our render code repeated in 3 classes, and that will only get worse as we add more.
Fortunately, this situation is exactly what inheritance is designed to solve.
Inheritance allows to organise our classes into hierarchies. This allows a class to inherit the functions and variables of its parent. For example, lets create a class that we could use to create our rock objects. We'll call this the Actor
class.
An actor is a common name for any simple class of things that can exist in our imagined world. It is where we will define the Render
function:
Next, lets create a class for our Goblins. Goblins also need the ability to be rendered, but with inheritance, we no longer need to recreate that functionality. Actor
already has that ability.
Goblins are just a more specific type of Actor
, so we can have our Goblin
class inherit all the abilities of the Actor
class.
Now, our Goblin
class has the Render
ability, without needing to write any additional code. It just inherits it from the parent class.
Hierarchical structures like these are very common in programming. There are many different terms used to describe the position of something within the hierarchy.
Phrases associated with family relationships are often used, such as parent, child, ancestor, descendant and more. For example:
Actor
is a parent or an ancestor of Goblin
Goblin
is a child or a descendant of Actor
Other popular terms include _sub class, base class and derived class. For example:
Goblin
is a sub class of Actor
Goblin
derives from Actor
Actor
is the base class of Goblin
This tree structure provides our classes with a powerful ability. We get to have our dedicated, specific classes, but they don't need to duplicate the more generic, shared functions. They can instead just inherit those functions and variables from their ancestors.
What is inheritance?
In our above example, lets imagine we create an object from our Goblin class.
Goblin Bonker;
Bonker is a Goblin, ie, it is an instance of the Goblin
class, therefore, it has access to the Attack()
function, as we've seen before.
The cool thing with inheritance is that, because the Goblin class is a child of the Actor class, all Goblin objects are also Actor objects. This means that Goblins have access to all the functions and variables of the Actor class, too.
Goblin Bonker;
// Available because Bonker is an Actor
Bonker.Render();
// Available because Bonker is a Goblin
Bonker.Attack();
So, with this class hierarchy, all Goblin objects are inherently also Actor objects. The opposite is not necessarily true - an Actor is not necessarily also a Goblin. It could just be a plain Actor, or it could be some other subclass of actor.
Actor BigRock;
// Available because BigRock is an Actor
BigRock.Render();
// But we can't do this, because BigRock is not a Goblin
BigRock.Attack();
If we have a Dog
class that inherits from the Animal
class, and we create a new object of type Dog
, which of the following is true?
If we have a Dog
class that inherits from the Animal
class, and we try to create a new object using the Animal
class, which of the following is true?
We haven't yet implemented our original design yet. Lets add the Dragon class, using the same approach:
Something should seem off here. The Dragon and Goblin classes both have the Move
, Attack
and DropLoot
functions. That's too much duplicate code.
Thankfully, with our new knowledge of inheritance, we might realise a way we can improve this design.
We shouldn't move that code into the Actor
class, because simple objects like rocks don't need it. Instead, we can move that shared code into a new class. We can have both Goblin and Dragon inherit from it. Lets call this new class Character
Now, we have multiple layers of inheritance. With this setup, any Dragon we create will have the abilities of three different types:
Dragon Dave;
// Dave is an Actor
Dave.Render();
// And a Character
Dave.Attack();
// And a Dragon
Dave.Fly();
That's enough theory for now - lets see how we can unlock the possibilities of inheritance.
We'll set up the above hierarchy in our code in the next lesson!
Become a software engineer with C++. Starting from the basics, we guide you step by step along the way