Inheritance
Build specialized classes on top of general ones and reuse their code.
10 min read
You will learn
- Derive a class from a base class
- Call a base constructor with base(...)
- Use protected members
- Recognize when inheritance is (and isn't) the right tool
Specialized versions of a general idea
A company has employees. Some employees are managers: they have everything an employee has (name, salary) plus a team. Rather than copy the employee code into a Manager class, C# lets Manager inherit from Employee.
class Employee
{
public string Name { get; }
public decimal Salary { get; protected set; }
public Employee(string name, decimal salary)
{
Name = name;
Salary = salary;
}
public string Introduce() => $"Hi, I'm {Name}";
}
class Manager : Employee
{
public List<Employee> Team { get; } = new();
public Manager(string name, decimal salary) : base(name, salary)
{
}
public void Hire(Employee e) => Team.Add(e);
}Employeeis the base class (or parent);Manageris the derived class (or child).Managerautomatically hasName,SalaryandIntroduce()— it inherits them.- It adds its own members:
TeamandHire.
var boss = new Manager("Grace", 9000);
boss.Hire(new Employee("Linus", 5000));
Console.WriteLine(boss.Introduce()); // Hi, I'm Grace — inherited method
Console.WriteLine(boss.Team.Count); // 1Calling the base constructor
A derived class must make sure the base part of the object is initialized. : base(...) passes arguments to the base class constructor, which runs first:
public Manager(string name, decimal salary) : base(name, salary)
{
// by now, Name and Salary are already set
}If the base class has a parameterless constructor, it's called automatically; otherwise : base(...) is required.
is-a: a derived object is a base object
Because every Manager is an Employee, you can use a manager wherever an employee is expected:
Employee e = new Manager("Grace", 9000); // ✅ allowed
List<Employee> staff = [new Employee("Linus", 5000), new Manager("Grace", 9000)];
Console.WriteLine(e is Manager); // True — check the actual type at run timeThe reverse isn't true: not every Employee is a Manager.
protected: for the family only
| Modifier | Accessible from |
|---|---|
private | This class only |
protected | This class and classes derived from it |
public | Everywhere |
In Employee, Salary has a protected set: managers' code (say, a GiveRaise method on a subclass) can change salaries, but outside code can't.
Every class inherits from object
If you don't specify a base class, it's object (System.Object). That's why every type has methods like ToString(), Equals() and GetType():
var e = new Employee("Linus", 5000);
Console.WriteLine(e.GetType().Name); // Employee
Console.WriteLine(e.ToString()); // "Employee" — the default; you'll override it next lessonsealed: no further inheritance
Mark a class sealed to prevent anyone deriving from it: sealed class Settings { ... }. string is sealed, for example.
Inheritance vs composition
Inheritance is powerful but creates tight coupling: changes to a base class ripple into every derived class. Use it for real is-a relationships. For has-a relationships, use composition — give the class a field holding another object:
class Car
{
private readonly Engine engine = new(); // a Car HAS an Engine — it isn't one
public void Start() => engine.Ignite();
}Favor composition
A common design guideline: favor composition over inheritance. Reach for inheritance when you need polymorphism (next lesson), not just to reuse a few methods.
Try it
C# runtime not loaded
Key takeaways
class Derived : Baseinherits all ofBase's members and adds its own.- Derived constructors pass arguments to the base with
: base(...). - A derived object can be used wherever the base type is expected (is-a).
protectedmembers are visible to derived classes; every class ultimately derives fromobject.- Prefer composition for has-a relationships.
Exercise
Animal is complete. Make Dog inherit from Animal: its constructor takes a name and a breed, passes the name to Animal's constructor, and stores the breed in a Breed property. Add a Bark method that returns "<name> says Woof!".
C# runtime not loaded
Hint 1
Inheritance syntax: class Dog : Animal { ... }
Hint 2
Animal has no parameterless constructor, so Dog's constructor must call it: public Dog(string name, string breed) : base(name) { ... }
Show solution
var animal = new Animal("Generic");
Console.WriteLine(animal.Describe());
class Animal
{
public string Name { get; }
public Animal(string name)
{
Name = name;
}
public string Describe() => $"{Name} is an animal";
}
class Dog : Animal
{
public string Breed { get; }
public Dog(string name, string breed) : base(name)
{
Breed = breed;
}
public string Bark() => $"{Name} says Woof!";
}Quiz
4 questions · 3 correct to pass1.What does `class Cat : Animal` mean?
2.How many base classes can a C# class have?
3.Who can access a protected member?
4.When is inheritance a good fit?
To complete this lesson
- ○ Solve the exercise
- ○ Pass the quiz (3/4 correct)