Intermediate · Inheritance, interfaces and records · topic 19 of 43 · 30 min
Abstract classes and polymorphism
Explanation
The idea of polymorphism
Polymorphism (Greek for "many forms") means you can write code against a general type and let each specific object do its own thing. A checkout page should not need a separate branch for UPI, cards and net banking. It should say "payment, process yourself", and each payment type knows how.
abstract classes
Sometimes the base class is only an idea. There is no such thing as a plain "Payment"; there is always a UPI payment or a card payment. Mark such a class abstract. You cannot create it with new, but you can use it as a variable type. An abstract method has no body; every non-abstract derived class must override it.
public abstract class Payment
{
public decimal Amount { get; }
protected Payment(decimal amount) => Amount = amount;
public abstract decimal Fee(); // no body: each type decides
public decimal Total() => Amount + Fee(); // normal method, shared
public override string ToString() => $"{GetType().Name}: {Amount} + fee {Fee()} = {Total()}";
}
public class UpiPayment : Payment
{
public UpiPayment(decimal amount) : base(amount) { }
public override decimal Fee() => 0m;
}
public class CardPayment : Payment
{
public CardPayment(decimal amount) : base(amount) { }
public override decimal Fee() => Math.Round(Amount * 0.02m, 2);
}
public class NetBankingPayment : Payment
{
public NetBankingPayment(decimal amount) : base(amount) { }
public override decimal Fee() => 10m;
}Polymorphism in action
Payment[] payments =
{
new UpiPayment(500m),
new CardPayment(1000m),
new NetBankingPayment(750m)
};
foreach (Payment p in payments)
Console.WriteLine(p);
// var x = new Payment(10m); // error CS0144: cannot create an instance of the abstract typeThe decision of which Fee() to run is made at run time, by looking at the real object. This is called dynamic dispatch or late binding. The loop does not change when you add a new WalletPayment class tomorrow, which is the real benefit: new features without editing old, tested code.
Overriding versus hiding versus overloading
| Term | What it is | Decided |
|---|---|---|
| Overloading | Same name, different parameters, in one class | At compile time, by argument types |
| Overriding | Derived class replaces a virtual/abstract method | At run time, by the object's real type |
| Hiding (new) | Derived class declares a member with the same name, no override | At compile time, by the variable's type |
Checking and converting types
Payment p = new CardPayment(200m);
if (p is CardPayment card)
Console.WriteLine($"Card fee: {card.Fee()}");
var maybe = p as UpiPayment; // null if p is not a UpiPayment
Console.WriteLine(maybe is null); // TrueCommon mistakes and fixes
- Not implementing an abstract method: error CS0534, the derived class does not implement the inherited abstract member. Add the override.
- Trying new on an abstract class: error CS0144. Create a concrete derived class.
- Calling an abstract or virtual method from the base constructor: the derived object is not fully set up yet, so it may see default values. Avoid it.
- Making a class abstract with no abstract members just to block new: a protected constructor or simply a normal class may be clearer.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Abstract classes and polymorphism · 1/7
In this lesson you will write code that works with many kinds of objects at once.
Prefer a video by a teacher? Find free videos on “C# polymorphism abstract class abstract method explained” on YouTube ↗
In real life: Calculating delivery charges for different courier partners
An Indian e-commerce seller ships through several courier partners. Each partner prices differently: by weight, by zone, or a flat rate. The order screen works with the abstract Courier type, so adding a new partner means adding one class.
Courier[] partners = { new FlatCourier(), new WeightCourier() };
foreach (var c in partners)
Console.WriteLine($"{c.Name}: Rs {c.Charge(2.5)}");
public abstract class Courier
{
public abstract string Name { get; }
public abstract decimal Charge(double kg);
}
public class FlatCourier : Courier
{
public override string Name => "QuickShip";
public override decimal Charge(double kg) => 60m;
}
public class WeightCourier : Courier
{
public override string Name => "KiloExpress";
public override decimal Charge(double kg) => 30m + 20m * (decimal)Math.Ceiling(kg);
}Practice (0/4 done)
Can you write new Shape() if Shape is abstract?
What does this print? Shape[] s = { new Square(2), new Circle(1) }; foreach (var x in s) Console.Write(x.Name() + " "); abstract class Shape { public abstract string Name(); } class Square : Shape { int a; public Square(int a) => this.a = a; public override string Name() => "Square"; } class Circle : Shape { int r; public Circle(int r) => this.r = r; public override string Name() => "Circle"; }
object o = "hello"; What is o as string?
Create an abstract class Notification with an abstract method Send(string to, string text) returning a string, and three classes: SmsNotification, EmailNotification and WhatsAppNotification, each returning text like "SMS to 98xxxx: Your OTP is 4321". Store them in a List<Notification> and send the same OTP through each.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Interfaces: contracts for behaviourInheritance, interfaces and records · same module
- Records and pattern matchingInheritance, interfaces and records · same module
- Virtual functions and polymorphismC++ Programming (modern C++ and DSA) · Operator overloading, inheritance and polymorphism
- Overriding and polymorphismJava Programming (Core to Spring Boot) · Inheritance, polymorphism and interfaces
- Abstract classesJava Programming (Core to Spring Boot) · Inheritance, polymorphism and interfaces
- Abstract classes, interfaces and good class designC++ Programming (modern C++ and DSA) · Operator overloading, inheritance and polymorphism
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is polymorphism?
Answer: One piece of code working with many types, each responding in its own way
Calls through a base type run each object's own override.
What must a non-abstract class do with an inherited abstract method?
Answer: Override it
Otherwise error CS0534.
When is the overridden method chosen?
Answer: At run time by the object's actual type
Virtual dispatch happens at run time.
Can an abstract class have a constructor and normal methods?
Answer: Yes
Abstract classes can contain state, constructors and implemented methods.
Payment p = new UpiPayment(10m); var c = (CardPayment)p; What happens?
Answer: InvalidCastException at run time
A direct cast to the wrong type throws; use is or as to check safely.
A base constructor calls a virtual function. Which version runs?Related
Answer: The base version, because the derived part is not built yet
During base construction the object behaves as a base object.
When is the overridden method to run chosen?Related
Answer: At run time, based on the actual object
That is dynamic dispatch.
Can you declare a variable of an abstract class type?Related
Answer: Yes, and assign it a subclass object
Payment p = new UpiPayment(…) is polymorphism.
From Abstract classes
Can an abstract class have a constructor and data members?Related
Answer: Yes; it just cannot be instantiated on its own
Abstract only means "cannot be created directly". It may still hold shared data and constructors for derived classes.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Inheritance, interfaces and records” before its exam: Interfaces: contracts for behaviour, Records and pattern matching.
- Module 5 exam: Inheritance, interfaces and records · 13 questions · 20 min, without help. 4 topics of this module still to finish first.
- Then the next module, Collections, generics and LINQ. 43 topics left in the course before the final exam.