- Create a derived class and use the keywords
virtual,overrideandbase - 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).
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)";
}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.
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;
}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.
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}");
}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.
| Criterion | Abstract class | Interface |
|---|---|---|
| How many a class can use | only one | as many as needed |
| Fields and state | allowed | not allowed |
| When to choose it | closely related classes share code | different classes share a capability |
Key points
class Dog : Animal—Dogderives fromAnimaland gets its members; a class has only one base class.- A derived class overrides a
virtualmethod withoverride;basecalls the parent's version. - You cannot create objects of an
abstractclass; 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.