Inheritance and Polymorphism in C#
Extending classes with inheritance, and overriding behavior with virtual and override.
2 min read
Inheritance lets one class build on another, reusing its members and specializing its behavior.
Basic inheritance
class Animal
{
public string Name;
public Animal(string name)
{
Name = name;
}
public void Eat()
{
Console.WriteLine($"{Name} is eating");
}
}
class Dog : Animal
{
public Dog(string name) : base(name) { }
public void Bark()
{
Console.WriteLine($"{Name} says woof!");
}
}
var dog = new Dog("Rex");
dog.Eat(); // inherited from Animal
dog.Bark(); // defined on DogDog : Animal means Dog inherits from Animal. The : base(name) in the constructor forwards the argument up to Animal's constructor — a derived class's constructor must always account for how its base class gets initialized.
C# only allows single inheritance for classes — one base class, no more. This is intentional; it avoids the "diamond problem" ambiguity that multiple class inheritance creates in other languages. Interfaces (a later lesson) are how C# gives you multiple-inheritance-like flexibility instead.
Overriding behavior: virtual and override
By default, a method in a derived class doesn't replace the base class's version for polymorphic calls — it just adds a new one. To let a subclass genuinely override behavior, the base method must be marked virtual:
class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Some generic animal sound");
}
}
class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}Polymorphism in action
The payoff is that code working with the base type automatically gets the derived behavior:
List<Animal> animals = new List<Animal> { new Animal(), new Dog() };
foreach (var animal in animals)
{
animal.MakeSound(); // "Some generic animal sound", then "Woof!"
}Even though the list is typed as List<Animal>, each element's actual type determines which MakeSound() runs. This is polymorphism: code written against the general Animal type works correctly no matter which specific subclass shows up at runtime.
sealed: preventing further overrides
class Dog : Animal
{
public sealed override void MakeSound()
{
Console.WriteLine("Woof!");
}
}sealed on an override stops any further subclass from overriding it again. It's a way of saying "this behavior is final" partway down an inheritance chain, useful when you want to guarantee a specific method can't be silently changed by something extending your class later.
Test what you just learned
4 quick questions. Get all of them right to unlock the next lesson.
You can take the quiz without an account — logging in just lets your result count toward your progress.