Lesson Objectives
At the end of this lesson, you will know…
- Why you might use inheritance.
- How to use inheritance and base classes
There is a lot of repetition in the class properties
Right now, we have seven classes in the Engine project: HealingPotion, Item, Location, Monster, Player, Quest, and Weapon.
You may have noticed that some of the classes have very similar properties. Some of the classes also represent the same type of thing. For instance:
- HealingPotion, Item, and Weapon all have the properties ID, Name, and NamePlural. They all also represent items that a player may collect during a game.
- Player and Monster share CurrentHitPoints and MaximumHitPoints. They are both “living creatures” in the game.
When you have classes that represent the same type of thing, and have similar properties (or functions, as we’ll see later) that mean the same thing, you may want to use inheritance – another aspect of object-oriented programming.
We’re going to make the Item class the base class for HealingPotion and Weapon, since all of those classes have the properties that are in the Item class.
Then, we’re going to create a new LivingCreature base class, to hold the shared CurrentHitPoints and MaximumHitPoints properties of the Monster and Player classes.
Here is how we do that.
Step 1: Start Visual Studio Express 2013 for Desktop, and open the solution.
Step 2: Double-click on the HealingPotion class, in the Engine project. Change line 9 to this:
public class HealingPotion : Item
Adding the colon and Item class name after the HealingPotion class name is how we show that HealingPotion has a base class of Item. So, all the public properties and methods from the Item class now automatically show up in the HealingPotion class, even after we delete the lines for the ID, Name, and NamePlural properties.
HealingPotion is now a “child class”, or “derived class”, from the Item class. Those are the common terms you’ll hear other programmers use, for classes that inherit from another class.
Now, we can remove the ID, Name, and NamePlural properties from HealingPotion, since they are in the base class.
One of the most popular benefits of a base class is that you don’t need to duplicate properties and methods in all of its child classes. Child classes have access to variables/properties/methods/etc. that are in the base class – as long as their scope is not “private”. Anything that is private is only visible inside the base class.
So, the ID, Name, and NamePlural properties are now “in” the HealingPotion class, because they are in its base class, and not private.
Step 3: Do the same thing that you just did to the HealingPotion class to the Weapon class – add the Item base class and delete the lines with the three properties that are already in the Item class.
Step 4: We don’t already have a class with the properties we have in common with the Monster and Player classes, so create a new class, named LivingCreature, with the integer properties for CurrentHitPoints and MaximumHitPoints. Be sure to make this class public. A base class needs to be at least as visible (with regards to its scope) as its child classes.
Step 5: Change the Monster and Player classes so they have LivingCreature as a base class (add the colon and LivingCreature to the lines that start with “public class”), and remove the CurrentHitPoints and MaximumHitPoints properties from those two classes – since they’ll now use the properties from the base class.
Step 6: In the UI project, view the code of the SuperAdventure form (right-click on SuperAdventure.cs). Notice that there is no red line under the Player CurrentHitPoints and MaximumHitPoints properties on lines 25, 26, and 31 – even though you just deleted those properties from the Player class. That’s because the class inherited those properties from its base class – LivingCreature.
Step 7: Start the program, so you can see that the CurrentHitPoints value is still correctly displayed on the screen.
Summary
Now you know how, and why, you would create base classes for the classes in your program. This is especially helpful when you write larger applications, and you want to make sure that classes that are similar all act in a similar manner.
Base classes also let you share functions (Lesson 09), so you don’t have to duplicate the same code in several places – and worry about accidentally mistyping something in one of them.
There are some more advanced conditions to what is visible from the base class, in the “child” classes. But we won’t get into those in this guide.
Source code for this lesson
Next Lesson: Lesson 08.1 – Setting properties with a class constructor
Previous lesson: Lesson 06.1 – Creating the remaining classes
All lessons: Learn C# by Building a Simple RPG Index
I just wanted to note:
In step 4, you should be explicit about adding ‘public’ to ‘class LivingCreature’ …
I got to step 6 and was still seeing red lines under the variables and realized it was because I did not declare the LivingCreature class as public.
Anyway,
Thanks!
You’re welcome. I’ve added a bit more description about the required public scope of the LivingCreature class.
I think I might have missed a step? In the last lesson I don’t think you told us to add the properties to the class’s. Like ID ect. So that is a little confusing.
In Step 2 of the previous lesson, I mention “Instead of manually typing in all the classes and properties from this page, get the source code for the classes from the link at the end of this lesson.” The link for the code is https://gist.github.com/ScottLilly/ade88e1a92a2ff8799f0
I’m getting an error message saying “Inconsistent accessibility: base class ‘item’ is less accessible than class ‘HealingPotion’
Make sure your Item class is defined as “public”, like this (on line 9, of Item.cs):
public class Item
By default, if you don’t add an “access modifier” (such as “public”, “private”, “internal”), a class is “internal”, which has less accessibility than “public”. And a base class cannot be less accessible than one of its child classes.
If that doesn’t fix the problem, please let me know.
What a nice, easy to understand introduction to inheritance. I am getting back into learning C# after a previous false start and so far your tutorials are great for reviewing the fundamentals.
Thank you!
Step 2 is oddly worded: “Change line 9 by to this:”
Also, in Step 2, you never explicitly tell us to delete the common “Item” properties out of “HealingPotion”. It’s easy to gather in the next few steps, but you may want to add something like that.
I am TOTALLY enjoying this series and learning a ton. I hit a major brick wall in self-teaching with regard to Class-Object interaction in C# and this has helped tremendously. I cannot thank you enough!
Thanks. I’m glad to hear this is helping you.
I fixed the grammar error and added some more information on removing the properties from the child class.
I know a lot of the basics of C# already from other tutorials and reading through Microsoft’s own articles, and in my pursuit of mastering C# I’ve come across forums where I’ve seen several people say it’s bad practice to make a lot of public variables, the question ofc being how do you then access variables in other classes, however do you agree that it is bad practice, I don’t really know what to believe. The public scope/protection level seems very useful and I currently don’t know of any other way to access variables in other classes.
What I often do is have properties with public “get” and private “set”. With the public “get”, the property value can be viewed by the user interface (usually in a separate project from the “engine” classes). The property value would be modified by calling a public function on the class – which has access to the private “set”, because it is in the same class.
For example, think of the CurrentHitPoints property in the Player class. The “get” would be public, to be displayed in the UI. To modify CurrentHitPoints, you would go through a public function in the Player class, such as:
public void TakeDamage(int hitPointsOfDamage)
TakeDamage can change the value of CurrentHitPoints, but could also have logic to make sure CurrentHitPoints is never negative (the lowest it would allow is zero). Because the “set” is private, everything that subtracts hit points would need to go through TakeDamage. So, we can be certain the value will never be below zero. If the “set” was public, the value could be changed anywhere in the program. Then, we would need to add zero-checking logic every place the code subtracted hit points.
Let me know if that helps make it clearer.
Great! I understand what you mean, thank you for the quick answer! Good analogies with the lessons.
You’re welcome! Let me know if you have any other questions.
I’m still a little confused as to why you would use a :Items ; base class. What would happen if I didn’t use a base class and just wrote the application without using it? Would it change anything or be constructed any differently?
There are two main reasons for using a base class:
1. Because we don’t want to have duplicate functions/properties in the classes that would be child classes. In future lessons, we are going to add some new functions to LivingCreature. By adding it in the base class, we do not need to add it to all the child classes. This saves us time and makes it less-likely to have bugs. Copy-pasting code into multiple classes is a common source of bugs. Sometimes a programmer forgets to copy all the changes to the classes that would be children (when you don’t use a base class). Then, that class “mysteriously” acts differently. By making the change to the base class, we can be certain the change appears in all the other (child) classes.
2. We want to have an Inventory property that contains a list of Item objects. Because HealingPotion inherits from Item, we can store a HealingPotion object in a property whose datatype is HealingPotion OR is Item. So, our Inventory property can be a List of Item objects. If we didn’t do use the base class, we would need to have separate properties for WeaponInventory (to hold Weapon objects) and HealingPotionInventory (to hold HealingPotion objects), etc.
Does that make sense?
HI Scott Lilly,
I am following your instructions carefully up to lesson 07.1 (where I am stuck with an error message – code CS1061)
‘Player’ does not contain a definition for ‘MaximumHitPoints’ and no accessible extension method ‘MaximumHitPoints’ accepting a first argument of type ‘Player’ could be found (are you missing a using directive or an assembly reference?)
Do you know what might be up?
Thanks
Josh
oops! I figured it out by checking my spelling!!! LOL!!!
No problem!
It says at the start that both the player class and the monster class have an ID property, but I couldn’t find a previous step that said to include ID in the Player class.
do i need to add ID to the player class or is it a mistake?
Hi Ben,
That was a mistake on my part. Player and Monster only share the hit point properties in the base class, not the ID. I corrected the lesson.
Thanks for pointing that out!
Hello Mr. Scott
I’m afraid to forget about what I just inherit from the base class.
So
I don’t delete those properties.
I just make them as comments.
/* Inherited properties
public int ID { get; set; }
ect
*/
And click the minus button.
Then it only display one line
/* Inherited properties …
Thank you for making this series.
I can’t wait to finish up all the lessons.
I just jumped right into here, from SoloLearn’s tutorial.
I know nothing about programing before.
This pandemic thing makes me learn a lot of new skills.
Stay healthy, Mr. Scott
You’re welcome!
It’s great that you are using this time to learn new skills. Commenting your unused code is a good way to help you remember when you move code. If you write larger programs, you might make many changes and want to delete those lines (so the classes are smaller and easier to read). But, if you use source control, you can always see the old versions of your program.
Stay safe, healthy, and keep on learning!