๐ WAYPOINT LESSON
Polymorphism: one call, many shapes
โญ beginnerโณ 14 min read๐ Lesson 39 of 85
`virtual` marks a method replaceable; `override` replaces it; the runtime picks by the object's actual type.
The dispatch problem
A method that processes many kinds must behave per-kind. Without language help you write type checks everywhere; with virtual/override the runtime does it:
class Shape
{
public virtual double Area() => 0.0;
}
class Circle : Shape
{
private double r;
public Circle(double radius) { r = radius; }
public override double Area() => Math.PI * r * r;
}
class Rect : Shape
{
private double w, h;
public Rect(double w, double h) { this.w = w; this.h = h; }
public override double Area() => w * h;
}
Now one loop handles every shape โ including kinds written after this loop existed:
var shapes = new List<Shape> { new Circle(1), new Rect(2, 3) };
double total = 0;
foreach (Shape s in shapes) total += s.Area(); // actual type decides
s.Area() dispatches on the object's runtime type: Circle's override for circles, Rect's for rectangles. Adding Triangle : Shape needs zero changes to the loop โ that is the payoff.
The rules that make it safe
virtualsays "subclasses may replace this"; without it,overridedoesn't compile.- An override keeps the base's signature. Callers can't tell override from original at the call site.
sealed overridestops further replacement.
Missing override is not an error โ the base implementation runs. That makes virtual a promise: the base version must be a sane default.