Method overriding happens when a subclass provides its own implementation of a method that's already defined in its parent class, replacing (or extending) the inherited behavior for objects of that subclass.
class Bird {
function move() {
return "The bird flies."
}
}
class Penguin extends Bird {
function move() { // overrides Bird's move()
return "The penguin swims (can't fly)."
}
}
bird = new Bird()
penguin = new Penguin()
print(bird.move()) // "The bird flies."
print(penguin.move()) // "The penguin swims (can't fly)."
Extending rather than fully replacing parent behavior is common — call the parent's version explicitly and add to it:
class Logger {
function log(message) {
print("[LOG] " + message)
}
}
class TimestampedLogger extends Logger {
function log(message) {
super.log(currentTime() + " — " + message) // calls the parent's version, adds a timestamp
}
}
Rules that typically apply to overriding (specifics vary slightly by language):
- The method name and parameter list (signature) must match the parent's exactly
- The overriding method generally cannot reduce visibility (you can't override a
publicmethod with aprivateone) - Some languages require an explicit
@Overrideannotation (Java) oroverridekeyword (C#) to catch accidental typos that would otherwise silently create a brand-new method instead of actually overriding the intended one - A method marked
final(or equivalent) cannot be overridden at all — used to lock in behavior that must never change in a subclass
Overriding is the mechanism that makes runtime polymorphism (covered in the Polymorphism chapter) possible in the first place.