Polymorphism: virtual and override
The same call, s.Area(), runs different code depending on what kind of object s actually is.
Watch it animatedStep through it, with the running line highlighted. Free with an account.The idea
The variable s has type Shape, but the object it points at is a Circle or a Square. For a virtual or abstract method, the runtime looks at the real object and runs that class's version.
Code
class Shape {
public:
virtual double area() const = 0;
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
double r = 1;
double area() const override { return M_PI * r * r; }
};
class Square : public Shape {
public:
double side = 2;
double area() const override { return side * side; }
};
int main() {
vector<unique_ptr<Shape>> shapes;
shapes.push_back(make_unique<Circle>()); shapes.push_back(make_unique<Square>()); shapes.push_back(make_unique<Circle>());
for (const auto& s : shapes)
cout << s->area() << "\n"; // the object decides which area() runs
}from abc import ABC, abstractmethod
import math
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
class Circle(Shape):
r = 1
def area(self) -> float: return math.pi * self.r * self.r
class Square(Shape):
side = 2
def area(self) -> float: return self.side * self.side
shapes = [Circle(), Square(), Circle()]
for s in shapes:
print(s.area()) # the object decides which area runsabstract class Shape {
public abstract double Area();
}
class Circle : Shape {
public double R = 1;
public override double Area() => Math.PI * R * R;
}
class Square : Shape {
public double Side = 2;
public override double Area() => Side * Side;
}
var shapes = new List<Shape> { new Circle(), new Square(), new Circle() };
foreach (Shape s in shapes)
Console.WriteLine(s.Area()); // the object decides which Area runsTips
- The loop never needs an if or a switch on the type. Adding a Triangle class requires no change to it.
- This lookup at run time is called dynamic dispatch.
In the .NET library
A method must be marked virtual or abstract in the base class and override in the derived class. Without those keywords C# binds the call at compile time.