Skip to content
wannacode

Inheritance

Problem

Two copies of the same code

The payroll program has an Employee class with a name, a salary and a method for a raise. Then you needed a manager too, who also gets a bonus. The fastest way was to copy Employee into a new class Manager and add the bonus.

A month later someone enters a raise of -10% instead of 10%. So you add a check to Employee. You forget it in Manager:

// in Employee
public void Raise(int percent)
{
if (percent > 0)
{
Salary += Salary * percent / 100;
}
}
// in Manager: a copy from before the check
public void Raise(int percent)
{
Salary += Salary * percent / 100;
}
Employee ivan = new Employee("Ivan", 2000);
Manager maria = new Manager("Maria", 3000, 500);
ivan.Raise(-10);
maria.Raise(-10);
Console.WriteLine(ivan);
Console.WriteLine(maria);
Output
Ivan: €2000
Maria: €2700

Ivan's salary is protected, but Maria's dropped by €300. The two classes are 90% the same, yet every fix has to be made twice.

The idea

The shared part goes in the parent

A manager is an employee, just with something extra. Say it in code: class Manager : Employee. In Manager you write only what is new, the bonus:

class Manager : Employee
{
public int Bonus { get; private set; }
public Manager(string name, int salary, int bonus) : base(name, salary)
{
Bonus = bonus;
}
}
Manager maria = new Manager("Maria", 3000, 500);
maria.Raise(-10);
maria.Raise(10);
Console.WriteLine(maria);
Console.WriteLine("Bonus: €" + maria.Bonus);
Output
Maria: €3300
Bonus: €500

Manager now has everything Employee has: a name, a salary, Raise() with the check, ToString(). That is why the -10% raise did not go through. The check is written once and works for both classes.

This is called inheritance. Employee is the parent (base class), and Manager is the child. The child takes everything from the parent and adds its own.

To check whether inheritance makes sense, use the sentence "X is a Y". "A manager is an employee" is true. "An invoice is an employee" is not, so the invoice does not inherit from Employee, even if it has an amount and a name.

Try it

What does the intern get?

Intern has nothing of its own except a constructor:

What will the program print?

class Intern : Employee
{
public Intern(string name, int salary) : base(name, salary)
{
}
}
Intern ana = new Intern("Ana", 1200);
ana.Raise(5);
Console.WriteLine(ana);
Answer

The idea

The parent comes first

name and salary are private in Employee. The child has them but cannot see them: to the child they are hidden, as they are to any other class. So how does Manager give them a value?

By calling the parent constructor:

public Manager(string name, int salary, int bonus) : base(name, salary)
{
Bonus = bonus;
}

: base(name, salary) calls the Employee constructor with these arguments. It sets up the name and the salary, and then the body of the Manager constructor sets up the bonus. You write base after the constructor's parentheses, before the body.

There is one object. It holds both the parent's part and the child's part, and each part is set up by its own constructor.

public Manager(string name, int salary, int bonus) : base(name, salary)
{
Bonus = bonus;
}
Manager maria = new Manager("Maria", 3000, 500);
Console.WriteLine(maria + ", bonus €" + maria.Bonus);
Step by step, in words
  1. new sets aside one object. It holds the Employee part and the Manager part.
  2. The Manager constructor starts with the three arguments.
  3. The parent comes first: base(name, salary) calls the Employee constructor, before the body.
  4. The Employee constructor sets up its part: name and salary.
  5. Only then does the body of Manager set up the bonus.
  6. There is one object, and each part is set up by its own constructor.
More precisely, if you are curious
  • Constructors are not inherited. Manager has no constructor Manager(string name, int salary) unless you write one.
  • If the parent has only a constructor with parameters and the child passes nothing, the program does not compile. The compiler does not know what name and what salary to give.

Try it

Which constructor runs first?

Here the child does not call the parent explicitly:

What will the program print?

class Account
{
public Account()
{
Console.WriteLine("Account opened");
}
}
class SavingsAccount : Account
{
public SavingsAccount()
{
Console.WriteLine("Interest: 3%");
}
}
SavingsAccount savings = new SavingsAccount();
Answer

Try it

Find the bug

Maria should have a salary of €3000 and a bonus of €500. But the program prints:

Output
Maria: €500

Which line is the bug on?

Pick the line with the bug.

The idea

protected: only for the children

At the end of the year, the manager's bonus is added to the salary. The method is in Manager, but the salary is private in Employee. A getter is not enough: you have to change it.

There is a third access level between private and public: protected. The class and its children can see such a member, and everyone else cannot:

class Employee
{
public string Name { get; private set; }
public int Salary { get; protected set; }
// ... the rest is as before
}
class Manager : Employee
{
// ... Bonus and the constructor
public void MergeBonus()
{
Salary += Bonus;
Bonus = 0;
}
}
Manager maria = new Manager("Maria", 3000, 500);
maria.MergeBonus();
Console.WriteLine(maria);
Console.WriteLine("Bonus: €" + maria.Bonus);
Output
Maria: €3500
Bonus: €0

In C# you more often open up not the whole property but only the setter: { get; protected set; }. Anyone can read the salary, but only Employee and its children can change it.

protected weakens the protection: any child can change the salary without going through the check in Raise(). That is why fields stay private by default. protected is for the cases where the child really has to touch the field.

More precisely, if you are curious
  • In C#, protected is only for the class and its children. There is also protected internal: the children plus everything in the same project.

Try it

What is missing?

An intern is an employee. What goes in the blank?

class Intern  Employee
{
    public Intern(string name, int salary) : base(name, salary)
    {
    }
}

The idea

One parent and a common ancestor

A class has exactly one parent. It cannot inherit from both Employee and Student. That is why inheritance is single.

The chain can be long. Intern inherits from Employee. And what does Employee inherit from, since it has no :? Every class without a parent inherits from object. This is the common parent of all classes. That is why even an empty class has methods:

class Ticket
{
}
Ticket a = new Ticket();
Ticket b = new Ticket();
Console.WriteLine(a.Equals(a));
Console.WriteLine(a.Equals(b));
Console.WriteLine(a.ToString());
Output
True
False
Ticket

Equals() comes from object. For now it only tells you whether two variables point to the same object.

ToString() comes from there too. If you do not write it, it returns the class name, which is why "Ticket" is printed above. In the "Classes and objects" module you wrote your own ToString() with override. Now you know that this replaces the version from object. What exactly override means is in the next lesson.

More precisely, if you are curious
  • A class with sealed before class cannot be inherited from. string is one.
  • object is a short name for System.Object. A variable of type object can point to any object at all: object anything = maria;.

Exercise

Child classes

Solve the tasks in your editor. The parent classes are from the "Classes and objects" module. If you do not have them at hand, write them again: they are short.

1. Family car. SimpleCar has a speed and a method Accelerate() that raises it by 10. Write FamilyCar, which inherits from SimpleCar, starts with 4 seats and has a method AddSeat(). Create a family car, speed it up and add a seat:

Output
Speed: 10 km/h
Seats: 5

2. Student. Person has a name, an age and Introduce(). Write Student, which inherits from Person and adds an average grade Grade (a decimal number). Use the parent constructor.

Output
I am Elena, 19 years old.
Grade: 5.5

3. Breakdance. DanceMove has a name, a duration in seconds and Perform(). Write BreakDanceMove with a complexity from 1 to 10 and a method ShowComplexity().

Output
Performing moonwalk for 5 seconds
Performing windmill for 12 seconds
windmill: complexity 8 out of 10

4. Electric car. Car has a brand, fuel in liters and the kilometers driven. Refuel(liters) adds fuel, and Drive(distance) uses 1 liter per 10 km and adds the kilometers (if there is not enough fuel, it says so and does not go). Write ElectricCar:

  • with no fuel, and with a battery that starts at 100%;
  • with an efficiency: how many km it drives on 1% of battery (5 for the "Tesla");
  • Charge() charges the battery to 100%;
  • DriveElectric(distance) uses battery instead of fuel and also adds the kilometers.
The kilometers are private in Car. How does the child change them? Hint: the card on protected.
Output
Skoda: 150 km, fuel 35 L
Tesla: 200 km, battery 60%
Not enough battery for 400 km
Tesla: 600 km, battery 20%

More tasks

  • Worker. Worker inherits from Person and adds a job title and a method Work():
Output
I am Peter, 34 years old.
My job: accountant
  • Intern with a mentor. Add a field with the mentor's name to Intern and pass it in the constructor, together with the name and the salary for the parent.

Test

Check yourself

1. class Manager : Employee. Which is true?
2. The field name is private in Employee. Can Manager write name = "Maria"; in one of its methods?
3. What does : base(name, salary) do in the Manager constructor?
4. How many parents can a class have?
5. Who can see a protected field?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·