OOP Dispatch: Dynamic Binding, Single & Double Dispatch
This article explains the concept of dispatch in object-oriented programming, including exam questions and key takeaways.
In a Nutshell
Dispatch refers to the process of selecting which method implementation actually gets executed when you call a method. Depending on the language and context, this selection happens either statically at compile time or dynamically at runtime—the foundation of polymorphism.
Core Definition
Dispatch is the resolution of a method call to its concrete implementation. With static dispatch (overloading), the compiler decides based on static types known at compile time. With dynamic dispatch (overriding), the runtime environment decides based on the actual object type, often using a vtable.
Dispatch variants:
- Single Dispatch: Selection based on the receiver object’s type
- Double Dispatch: Selection based on two runtime types (Visitor Pattern)
- Multiple Dispatch: Selection based on multiple runtime arguments
Dynamic binding enables polymorphism and the Open Closed Principle, but requires correct contracts following the Liskov Substitution Principle. Static dispatch offers predictability and performance, while dynamic dispatch provides flexibility and extensibility.
Exam-Relevant Topics
- Static Dispatch: Overloading, compile-time decision
- Dynamic Dispatch: Overriding, runtime decision
- vtable: Dispatch table for polymorphic calls
- Single Dispatch: Only receiver type determines method
- Double Dispatch: Both receiver and parameter types matter
- Visitor Pattern: Implements Double Dispatch
- Performance: Static dispatch faster than dynamic
- Key distinction: Overloading vs Overriding
Core Components
- Virtual Method Table (vtable): Dispatch table for polymorphic methods
- Single Dispatch: Standard OOP dispatch mechanism
- Double Dispatch: Visitor Pattern for complex type relationships
- Method Overriding: Dynamic binding through inheritance
- Method Overloading: Static binding at compile time
- Runtime Type Information (RTTI): Type information available at runtime
- Dynamic Binding: Resolution at runtime
- Static Binding: Resolution at compile time
Practical Examples
Single Dispatch (Standard OOP)
// Single Dispatch - only the receiver type decides
abstract class Animal {
abstract void makeSound();
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Woof!");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow!");
}
}
// Dynamic binding at runtime
Animal animal = new Dog(); // Static type: Animal, Dynamic type: Dog
animal.makeSound(); // Output: "Woof!" (Single Dispatch)
Double Dispatch with Visitor Pattern
// Double Dispatch - both receiver and parameter decide
interface Animal {
void accept(Visitor visitor);
}
class Dog implements Animal {
@Override
public void accept(Visitor visitor) {
visitor.visit(this); // Double Dispatch
}
}
class Cat implements Animal {
@Override
public void accept(Visitor visitor) {
visitor.visit(this); // Double Dispatch
}
}
interface Visitor {
void visit(Dog dog);
void visit(Cat cat);
}
class Veterinarian implements Visitor {
@Override
public void visit(Dog dog) {
System.out.println("Examining dog: administering vaccination");
}
@Override
public void visit(Cat cat) {
System.out.println("Examining cat: trimming claws");
}
}
// Usage
Animal[] animals = {new Dog(), new Cat()};
Visitor vet = new Veterinarian();
for (Animal animal : animals) {
animal.accept(vet); // Double Dispatch
}
// Output:
// Examining dog: administering vaccination
// Examining cat: trimming claws
Static vs Dynamic Dispatch
class Calculator {
// Static Dispatch (Overloading)
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
class PolymorphicCalculator {
// Dynamic Dispatch (Overriding)
public int compute(int a, int b) {
return a + b;
}
}
class Multiplier extends PolymorphicCalculator {
@Override
public int compute(int a, int b) {
return a * b;
}
}
// Static Dispatch at compile time
Calculator calculator = new Calculator();
int result1 = calculator.add(1, 2); // Compile: add(int, int)
// Dynamic Dispatch at runtime
PolymorphicCalculator poly = new Multiplier();
int result2 = poly.compute(3, 4); // Runtime: Multiplier.compute()
Advantages and Disadvantages
Advantages of Dynamic Dispatch
- Flexibility: Runtime polymorphism enables extensible systems
- Maintainability: Add new types without modifying existing code
- Abstraction: Treat different types uniformly
- Open Closed Principle: Extend behavior without changing code
Disadvantages
- Performance: Runtime overhead from vtable lookup
- Complexity: Harder to understand and debug
- Memory: Additional vtable structures consume memory
- Error-proneness: Runtime errors instead of compile-time errors
Dispatch Mechanisms Across Languages
Java
// Standard: Single Dispatch with vtable
// Double Dispatch via Visitor Pattern
interface Shape {
double area();
void accept(Visitor visitor);
}
C++
// Direct Support: Multiple Dispatch
#include <boost/variant.hpp>
struct DoubleDispatcher {
void collide(Asteroid& a, Spaceship& s) { /* ... */ }
void collide(Spaceship& s, Asteroid& a) { /* ... */ }
};
Python
# Duck Typing: Dynamic resolution
class Animal:
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return "Woof!"
# Dynamic binding at runtime
def animal_sound(animal):
return animal.make_sound() # Dispatch at runtime
Common Exam Questions
-
What is the difference between Single and Double Dispatch? Single Dispatch considers only the receiver type, while Double Dispatch considers both receiver and parameter types.
-
How does a vtable work? A vtable is an array of function pointers that resolves polymorphic method calls at runtime.
-
When do you use the Visitor Pattern? When operations must be separated from the data structure and Double Dispatch is required.
-
Why is dynamic dispatch slower than static dispatch? Because runtime vtable lookup is required instead of direct method calls determined at compile time.
Key References
- https://en.wikipedia.org/wiki/Dynamic_dispatch
- https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html
- https://refactoring.guru/design-patterns/visitor
Continue Your OOP Learning Path
All OOP articles are now complete. Return to the first article: OOP Fundamentals.



