65. Inheritance#
Inheritance, in object oriented languages, gives us two things:
Code reuse: It allows us to re-use code from the superclass in the subclass. We say that the subclass inherits the members of the superclass.
Subtype polymorphism: It makes the subclass substitutable for the superclass. We say that the subclass inherits the type of the superclass.
Warning
If you don’t need both of these things, then don’t use inheritance. If you want code reuse, then use composition. If you want subtype polymorphism, then use interfaces.
Note
The terms ‘parent class’ and ‘base class’ are synonyms of the term ‘superclass’. The terms ‘child class’ and ‘derived class’ are synonyms of the term ‘subclass’.
Inheritance is a binary relationship where one class inherits its members and type from another. Consider the following example:
public class Animal
{
public string Name { get; set; }
public void Eat()
{
Console.WriteLine($"{Name} is eating.");
}
}
public class Dog : Animal
{
public void Bark()
=> Console.WriteLine($"{Name} is barking.");
}
In the example above, Dog
inherits from Animal
.
Dog
is the subclass and Animal
is the superclass.
The property Name
and the method Eat
are both ‘inherited’ from Animal
.
This means that we can access the members defined in Animal
on objects of type Dog
.
Dog dog = new Dog() { Name = "Fido" };
dog.Eat();
Fido is eating.
Notice how we can call the Eat
method on a Dog
even though it was defined in Animal
. This is inheritance of members at display.
Of course, we can also access the members that are only defined in Dog
.
dog.Bark();
Fido is barking.
However, inheritance also implies inheriting type. Dog
doesn’t just inherit Animal
’s members, it also becomes a subtype of Animal
. This enables subtype polymorphism. Dog
can be treated as an Animal
and used wherever an Animal
is expected.
Animal animal = new Dog() { Name = "Rocky" };
animal.Eat();
Rocky is eating.
However, since the method Bark
is only defined in Dog
and not Animal
we can only call the Bark
method when our compile-time type is Dog
.
animal.Bark();
(1,8): error CS1061: 'Animal' does not contain a definition for 'Bark' and no accessible extension method 'Bark' accepting a first argument of type 'Animal' could be found (are you missing a using directive or an assembly reference?)
Tip
Return to the chapter on run-time types vs compile-time types if the terminology is confusing.
Since Animal
is a class we can also of course also instantiate that.
Animal animal = new Animal() { Name = "Rocky" };
Warning
Inheritance is often touted as a mechanism to model real-world relationships. However, viewing real-world relationships as strictly hierarchical, as inheritance suggests, can lead to misunderstandings and overly complicated designs. The world around us is full of complex, cross-cutting relationships that cannot be easily encapsulated within a hierarchy.
Consider the statement “a dog is an animal”. While this seems straightforward and easily modeled as a hierarchy (Dog : Animal
), when we introduce additional facets of reality, like roles (e.g. a pet, a police dog, a stray dog), this hierarchical model quickly becomes convoluted. A dog can fulfill roles like a pet, a police dog, or a stray dog, at different times or even simultaneously. These roles do not fit neatly into an inheritance hierarchy.
In later chapters we will discuss the fragile base class problem and the maxim prefer composition over inheritance. For now, just remember that if all you want is subtype polymorphism, it’s better to use interfaces, which provide the contract for behavior without inheriting unwanted members or being tied to the parent’s evolution.
Note
While a class can implement multiple interfaces, it can only inherit from a single class.
See also
Some languages, like C++, but not C#, support ‘multiple inheritance’. Allowing subclasses to have multiple parents leads to a problem known as ‘The Diamond Problem’ which different languages have different ways of handling.
Key point
Inheritance allows a class to inherit the members and type of another class. Use inheritance only if you need both these things.