19-Soft-B17 Data Visualization · December 2014
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.
Method overriding occurs when a subclass provides a new implementation for a method that is already defined, with the identical signature (same name, same parameter types and count, compatible return type), in one of its superclasses. Which implementation actually runs is resolved at run time, based on the actual (dynamic) type of the object the method is called on, regardless of the declared (static) type of the reference used to call it — this is dynamic dispatch, and it is the mechanism that makes runtime polymorphism possible: code written against a base-class reference automatically picks up whichever subclass's behaviour the actual object provides. Method overloading, by contrast, occurs when a single class (or a class and its superclass together) declares multiple methods that share the same name but differ in their parameter lists (different number, order, or types of parameters). Which overload is invoked is resolved at compile time, purely from the static types of the arguments supplied at the call site — there is no run-time decision involved, and the return type alone is not enough to distinguish overloads in most languages.
A concrete example makes the distinction sharp. Consider a base class Shape with a method double area(), and a subclass Circle extends Shape that also declares double area() with the exact same signature but computes πr² instead of the base class's default (say, zero). This is overriding: given Shape s = new Circle(3);, the call s.area() invokes Circle's implementation at run time, even though the compile-time type of s is Shape — the object's actual (dynamic) type governs. Now consider the same Shape class declaring two different methods both named resize: void resize(double factor) and void resize(double newWidth, double newHeight). This is overloading: calling shape.resize(2.0) versus shape.resize(4.0, 3.0) is decided purely by how many arguments (and of what type) are written at the call site, at compile time, with no relationship to inheritance or dynamic dispatch at all — indeed, a class need not have any subclasses whatsoever to use overloading.
The two mechanisms serve fundamentally different purposes: overriding supports polymorphism — "the same call, different behaviour depending on what kind of object you actually have" — while overloading supports convenience/readability — "the same conceptual operation, offered with several different parameter shapes so the caller can supply whichever inputs are most natural." A common point of confusion is that both let you call "the same-named method" and get different behaviour, but overriding depends on the receiver's run-time type while overloading depends only on the compile-time types of the arguments at the call site — which is also why overloading, unlike overriding, requires no inheritance relationship at all.