Skip to content
Educora
Intermediate20 min7 / 16

Inheritance, interfaces and polymorphism

Derive new classes from existing ones, override methods with `virtual` and `override`, and use abstract classes and interfaces so one piece of code works with many kinds of objects.

Check yourself
In this lesson you will learn
  • Create a derived class and use the keywords virtual, override and base
  • Explain what abstract classes and abstract methods are for
  • Define an interface and implement it in several classes
  • Explain polymorphism with examples

A game has a dog, a cat and a parrot. They all have names and can introduce themselves, but each makes a different sound. Instead of copying the same code three times, we put the shared part into a base class and write the differences in derived classes. Then we handle all the animals in one loop with the same code — one of the most powerful ideas in object-oriented programming.

Inheritance: virtual and override

Writing class Dog : Animal means that Dog derives from Animal: it receives all of the parent's public members. A method marked virtual in the base class can be overridden in a derived class with override. The base keyword lets you call the parent's version. With primary constructors, the argument is passed straight to the parent's constructor: : Animal(name).

C#
List<Animal> pets = [new Dog("Rex"), new Cat("Mestan"), new Animal("Nemo")];

foreach (Animal pet in pets)
    Console.WriteLine(pet.Introduce());

class Animal(string name)
{
    public string Name => name;
    public virtual string Speak() => "...";
    public virtual string Introduce() => $"I am {Name} and I say {Speak()}";
}

class Dog(string name) : Animal(name)
{
    public override string Speak() => "Woof!";
}

class Cat(string name) : Animal(name)
{
    public override string Speak() => "Meow!";
    public override string Introduce() => base.Introduce() + " (and ignores you)";
}
Expected output
I am Rex and I say Woof!
I am Mestan and I say Meow! (and ignores you)
I am Nemo and I say ...

Notice that the list's type is List<Animal>, yet when pet.Introduce() is called, each object uses its own Speak method. The same call giving different results depending on the object's real type is called polymorphism. The loop knows nothing about dogs, cats or a parrot you might add later — and it does not need to.

Abstract classes

Sometimes the base class is not complete on its own: you cannot compute the area of a “shape” in general, only of a specific rectangle or circle. Such a class is declared abstract. You cannot create objects from it (new Shape() gives error CS0144), and every derived class must implement its body-less abstract methods — otherwise you get error CS0534.

C#
using System.Globalization;

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

Shape[] shapes = [new Rectangle(4, 3), new Square(5), new Circle(1)];
foreach (Shape s in shapes)
    Console.WriteLine($"{s.GetType().Name}: area {s.Area():F2}");

abstract class Shape
{
    public abstract double Area();
}

class Rectangle(double width, double height) : Shape
{
    public override double Area() => width * height;
}

class Square(double side) : Rectangle(side, side);

class Circle(double radius) : Shape
{
    public override double Area() => Math.PI * radius * radius;
}
Expected output
Rectangle: area 12.00
Square: area 25.00
Circle: area 3.14
Square derives from Rectangle and reuses its Area method as it is — it did not even need a body.

Interfaces

An interface is a contract: it says which methods and properties a class must have, but not how they work. Interface names traditionally start with the letter I: INotifier, IComparable. A class accepts the contract by writing : INotifier and must implement all of its members. Even completely unrelated classes can implement the same interface.

C#
List<INotifier> notifiers =
[
    new EmailNotifier("aysel@example.com"),
    new SmsNotifier("+994 50 000 00 00")
];

foreach (INotifier n in notifiers)
    n.Send("Your order has shipped!");

interface INotifier
{
    void Send(string message);
}

class EmailNotifier(string address) : INotifier
{
    public void Send(string message) => Console.WriteLine($"Email to {address}: {message}");
}

class SmsNotifier(string phone) : INotifier
{
    public void Send(string message) => Console.WriteLine($"SMS to {phone}: {message}");
}
Expected output
Email to aysel@example.com: Your order has shipped!
SMS to +994 50 000 00 00: Your order has shipped!

If you need Telegram notifications tomorrow, you only write a new TelegramNotifier class that implements INotifier — the loop does not have to change. .NET itself is full of interfaces: IComparable<T> makes objects sortable, and IEnumerable<T> lets you go through them with foreach.

CriterionAbstract classInterface
How many a class can useonly oneas many as needed
Fields and stateallowednot allowed
When to choose itclosely related classes share codedifferent classes share a capability

Key points

  • class Dog : Animal — Dog derives from Animal and gets its members; a class has only one base class.
  • A derived class overrides a virtual method with override; base calls the parent's version.
  • You cannot create objects of an abstract class; derived classes implement its abstract methods.
  • An interface is a contract; a class can implement several interfaces.
  • Polymorphism: the same call behaves differently depending on the object's real type.

Check yourself

10 questions. Every correct answer earns XP.

1 / 10
Which keyword is used in a derived class to override the parent's method?