Polymorphism in object-oriented programming is enabled by two distinct mechanisms known as overloading and overriding. Method overloading, the form of compile-time polymorphism, occurs when multiple methods share the same name but differ in their parameter lists within the same class. For instance, a class might define both an add method accepting two integers and another accepting two doubles, and the compiler selects the correct version based on the argument types at the call site.
Method overriding is the run-time counterpart: a subclass provides a specific implementation of a method already declared in its superclass. When a Dog class extends Animal and overrides speak to print "Woof", the method called depends on the actual object type at runtime, not the declared reference type. This is what enables a single method call to produce different behavior depending on the underlying object.
The distinction between overloading and overriding runs deeper than their names suggest. Overloading involves compile-time binding within the same class with different parameters and possibly different return types, while overriding involves runtime binding across parent and child classes with identical signatures and return types that must be the same or covariant. Overloading is therefore static polymorphism, and overriding is dynamic polymorphism.
Underlying overriding is the concept of virtual methods. In C++, a method declared with the virtual keyword can be overridden by subclasses, with the call resolved at runtime through dynamic dispatch. In Java, all non-static, non-final methods are virtual by default, while in C# the virtual keyword must be used explicitly. A pure virtual function in C++, written as virtual void draw() = 0, has no implementation and forces subclasses to provide one, and a class containing such a function becomes abstract. These mechanisms together form the foundation of late binding, where the system checks the actual object type rather than the declared type when dispatching a method call, in contrast to early binding used for overloaded, static, and final methods. Virtual methods are also key to design patterns such as the Template Method.