Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartSwiggyRazorpayPhonePe

Polymorphism - Compile-Time (Overloading) vs Runtime (Overriding)

Choose your preparation mode3 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
🎯
Polymorphism - Compile-Time (Overloading) vs Runtime (Overriding)
mediumOOPAmazonGoogleMicrosoft

Imagine a smartphone app that can respond differently to a tap depending on the context - sometimes opening a photo, other times dialing a number. This flexibility is powered by polymorphism, a core OOP concept.

💡 Beginners often confuse overloading and overriding because both involve methods with the same name but differ in when and how the method to execute is chosen. Overloading is decided at compile time based on method signatures, while overriding is decided at runtime based on the actual object's class.
📋
Interview Question

Explain the difference between compile-time polymorphism (method overloading) and runtime polymorphism (method overriding) in object-oriented programming. How do they work internally, and what are their typical use cases?

Method Overloading: same method name, different parameters, resolved at compile timeMethod Overriding: subclass provides specific implementation, resolved at runtime via dynamic dispatchBinding: static (compile-time) vs dynamic (runtime) and role of vtable in overriding
💡
Scenario & Trace
ScenarioA payment processing system where the 'processPayment' method can accept different types of payment details (credit card, UPI, wallet).
At compile time, the compiler selects the correct 'processPayment' method based on the parameter types (overloading). At runtime, if a subclass overrides 'processPayment' for a specific payment type, the overridden method is invoked via dynamic dispatch (overriding).
ScenarioA graphics application where a base class 'Shape' has a method 'draw'. Different shapes like Circle and Rectangle override 'draw' to render themselves appropriately.
The program holds references to 'Shape' but at runtime calls the overridden 'draw' method of the actual shape object, enabling polymorphic behavior (runtime overriding).
  • What happens if overloaded methods differ only by return type?
  • What if a subclass overloads a method instead of overriding it?
  • How does polymorphism behave with static methods or private methods?
⚠️
Common Mistakes
Confusing overloading with overriding as the same concept

Interviewer doubts candidate’s grasp of polymorphism basics

Emphasize that overloading is compile-time and overriding is runtime polymorphism

Believing overriding can happen without inheritance

Interviewer questions candidate’s understanding of OOP hierarchy

Clarify that overriding requires subclassing and method signature matching

Thinking overloading is resolved at runtime

Candidate fails to explain static vs dynamic binding correctly

Explain that overloading is resolved by the compiler using method signatures

Assuming private or static methods can be overridden

Interviewer flags misunderstanding of method visibility and binding

Explain that private and static methods are bound statically and cannot be overridden

🧠
Basic Definition - What It Is
💡 This level covers the fundamental distinction you must clearly state to show basic understanding.

Intuition

Overloading is choosing among methods with the same name but different parameters at compile time; overriding is choosing the method implementation at runtime based on the object's actual type.

Explanation

Polymorphism allows objects to be treated as instances of their parent class while behaving differently based on their actual subclass. Compile-time polymorphism, or method overloading, means having multiple methods with the same name but different parameter lists within the same class. The compiler decides which method to call based on the arguments provided. Runtime polymorphism, or method overriding, happens when a subclass provides its own version of a method declared in the parent class. The method to execute is determined at runtime depending on the actual object's type, enabling dynamic behavior.

Memory Hook

💡 Think of overloading as choosing a tool from a toolbox by size (parameters) before starting work (compile time), and overriding as choosing the right tool during the job based on the material (runtime object type).

Illustrative Code

class Calculator:
    def add(self, a, b):
        return a + b

    def add(self, a, b, c=0):  # Overloading by default args
        return a + b + c

class AdvancedCalculator(Calculator):
    def add(self, a, b, c=0):  # Overriding
        print("Using AdvancedCalculator's add")
        return super().add(a, b, c)

calc = AdvancedCalculator()
print(calc.add(1, 2))
print(calc.add(1, 2, 3))

Interview Questions

How do you distinguish overloading from overriding?
  • Overloading: same method name, different parameters, resolved at compile time
  • Overriding: subclass method replaces parent method, resolved at runtime
Depth Level
Interview Time30 seconds
Depthbasic

Covers the core definitions and differences; sufficient for screening rounds.

Interview Target: Minimum floor - never go below this

Knowing only this helps pass initial screening but won't impress in detailed technical interviews.

🧠
Mechanism Depth - How It Works
💡 This level explains internal workings and is expected in product company interviews.

Intuition

Overloading is resolved by the compiler using static binding, while overriding uses dynamic binding via vtables or equivalent mechanisms at runtime.

Explanation

In method overloading, the compiler uses the method signature (name + parameter types) to select the appropriate method during compilation. This is static binding because the decision is fixed before execution. Overriding involves a subclass redefining a method from its superclass. At runtime, the program uses dynamic dispatch to invoke the correct method based on the actual object's type. This is typically implemented using a virtual method table (vtable) that maps method calls to the correct function pointers. Languages like Java and C++ use vtables to enable this dynamic behavior. Overriding enables polymorphic behavior where the same method call can result in different behaviors depending on the object's class.

Memory Hook

💡 Imagine overloading as choosing a recipe before cooking (compile time), and overriding as adapting the recipe while cooking based on available ingredients (runtime).

Illustrative Code

class Shape:
    def draw(self):
        print("Drawing a generic shape")

class Circle(Shape):
    def draw(self):  # Overriding
        print("Drawing a circle")

class Rectangle(Shape):
    def draw(self):  # Overriding
        print("Drawing a rectangle")

shapes = [Circle(), Rectangle(), Shape()]
for shape in shapes:
    shape.draw()  # Runtime polymorphism via overriding

Interview Questions

What internal mechanisms enable overriding but not overloading?
  • Overriding uses dynamic dispatch and vtables for runtime method resolution
  • Overloading uses static binding resolved by the compiler
  • Overriding requires inheritance and method signature matching
Depth Level
Interview Time2-3 minutes
Depthintermediate

Demonstrates understanding of binding types, vtables, and runtime behavior; expected for FAANG on-sites.

Interview Target: Target level for FAANG on-sites

Mastering this level distinguishes you from most candidates.

📊
Explanation Depth Levels
💡 Choose depth based on interview stage and company expectations.
LevelInterview TimeSuitable ForRisk
Basic Definition30sScreening callToo shallow for on-site interviews
Mechanism Depth2-3 minutesOn-site interviews at FAANG and top product companiesRequires solid understanding; missing details can lose points
💼
Interview Strategy
💡 Use this guide to structure your explanation clearly and confidently before every interview.

How to Present

Start with a clear definition of polymorphism and the two types: overloading and overriding.Give a relatable example or analogy to make the concept tangible.Explain the internal mechanism: static binding for overloading, dynamic binding for overriding.Discuss common edge cases and clarify misconceptions.

Time Allocation

Definition: 30s → Example: 1min → Mechanism: 2min → Edge cases: 30s. Total ~4min

What the Interviewer Tests

Interviewer checks if you can clearly differentiate overloading vs overriding, explain when each applies, and describe how the language/runtime handles method calls.

Common Follow-ups

  • Can you explain what happens if a subclass overloads a method instead of overriding it?
  • How do static methods relate to polymorphism?
💡 These follow-ups test deeper understanding and ability to handle tricky scenarios.
🔍
Pattern Recognition

When to Use

Asked when interviewer wants to test understanding of polymorphism, method dispatch, or OOP fundamentals.

Signature Phrases

'Explain compile-time vs runtime polymorphism''Compare method overloading and overriding''What happens when a subclass overrides a method?'

NOT This Pattern When

Similar Problems

Practice

(1/5)
1. Given the following Python code using the Decorator Pattern, what is the output of print(coffee.description()) and print(coffee.cost()) after wrapping a SimpleCoffee with MilkDecorator (amount=2) and then SugarDecorator (amount=1)?
easy
A. Coffee, Milk(2), Sugar(1) 6.3
B. Coffee, Sugar(1), Milk(2) 5.8
C. Coffee, Sugar(1), Milk(2) 6.3
D. Coffee, Milk(2), Sugar(1) 5.8

Solution

  1. Step 1: Trace description calls

    Starting from SugarDecorator: description() calls MilkDecorator.description(), which calls SimpleCoffee.description() returning "Coffee". Then MilkDecorator adds ", Milk(2)", SugarDecorator adds ", Sugar(1)" -> "Coffee, Milk(2), Sugar(1)".
  2. Step 2: Trace cost calls

    SimpleCoffee.cost() = 5. MilkDecorator adds 0.5 * 2 = 1. SugarDecorator adds 0.3 * 1 = 0.3. Total cost = 5 + 1 + 0.3 = 6.3.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Description order matches wrapping order; cost sums correctly [OK]
Hint: Decorator calls chain in wrapping order [OK]
Common Mistakes:
  • Mixing order of decorators in description
  • Forgetting to multiply cost by amount
2. You need to create different types of vehicles (cars, bikes) that share a common interface, and sometimes you want to create entire families of related vehicles (e.g., electric car + electric bike) ensuring consistency. Which design pattern best fits this requirement?
easy
A. Builder Pattern, because it constructs complex objects step-by-step.
B. Abstract Factory Pattern, because it creates families of related objects ensuring consistency.
C. Factory Pattern, because it creates simple objects based on a type parameter.
D. Singleton Pattern, because it ensures only one instance of each vehicle type.

Solution

  1. Step 1: Understand the requirement for families of related objects

    The problem states the need to create related vehicles (e.g., electric car and electric bike) that belong to a family and must be consistent.
  2. Step 2: Match pattern to requirement

    Abstract Factory is designed to create families of related objects, ensuring that the created objects are compatible and consistent.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Abstract Factory creates related object families, Factory creates single objects [OK]
Hint: Families of related objects -> Abstract Factory [OK]
Common Mistakes:
  • Confusing Factory with Abstract Factory
  • Using Builder for simple object creation
3. Given the following Python code using the Builder pattern, what is the output of print(house) after constructing a basic house with the Director?
easy
A. House parts: Walls, Roof
B. House parts: Walls, Roof, Pool
C. House parts: Roof, Walls
D. House parts: Pool

Solution

  1. Step 1: Trace Director.construct_basic_house()

    The Director calls build_walls() and build_roof() on the builder, adding "Walls" and "Roof" to the house parts.
  2. Step 2: Check the final house parts list

    The house parts list contains ["Walls", "Roof"]. The pool is not added in this method.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Only walls and roof are added in basic house construction [OK]
Hint: Basic house adds walls and roof only [OK]
Common Mistakes:
  • Assuming pool is added by default
  • Mixing order of parts
4. Given the following Python code using deep copy, what will be printed after modifying the copy's scores list?
import copy

class Profile:
    def __init__(self, name, scores):
        self.name = name
        self.scores = scores

    def __deepcopy__(self, memo):
        new_name = copy.deepcopy(self.name, memo)
        new_scores = copy.deepcopy(self.scores, memo)
        return Profile(new_name, new_scores)

original = Profile('Alice', [10, 20])
copy_obj = copy.deepcopy(original)
print('Original scores:', original.scores)
print('Copy scores:', copy_obj.scores)
copy_obj.scores.append(30)
print('After modifying copy scores:')
print('Original scores:', original.scores)
print('Copy scores:', copy_obj.scores)
easy
A. Original scores: [10, 20] Copy scores: [10, 20] After modifying copy scores: Original scores: [10, 20, 30] Copy scores: [10, 20, 30]
B. Original scores: [10, 20] Copy scores: [10, 20] After modifying copy scores: Original scores: [10, 20] Copy scores: [10, 20, 30]
C. Original scores: [10, 20] Copy scores: [10, 20] After modifying copy scores: Original scores: [10, 20] Copy scores: [10, 20]
D. Original scores: [10, 20] Copy scores: [10, 20, 30] After modifying copy scores: Original scores: [10, 20] Copy scores: [10, 20, 30]

Solution

  1. Step 1: Trace initial print statements

    Both original.scores and copy_obj.scores start as [10, 20], so first two prints show identical lists.
  2. Step 2: Trace modification and final prints

    copy_obj.scores.append(30) modifies only the copy's scores list because deep copy created a new list. Original remains [10, 20]. Final prints reflect this separation.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Deep copy prevents shared nested list -> original unchanged [OK]
Hint: Deep copy isolates nested mutable objects [OK]
Common Mistakes:
  • Assuming append affects original due to shared reference
5. Imagine a class responsible for both data persistence and data validation. When a change in validation rules occurs, trace the impact on the class and explain what happens step-by-step.
easy
A. Only the validation methods need modification; persistence remains unaffected, so SRP is maintained.
B. Changing validation rules forces modifying the entire class, risking unintended side effects on persistence logic.
C. Validation changes automatically propagate to persistence without code changes due to tight coupling.
D. Persistence logic will break because validation and persistence are tightly integrated and inseparable.

Solution

  1. Step 1: Identify responsibilities

    The class handles both validation and persistence, two distinct reasons to change.
  2. Step 2: Trace change impact

    Changing validation rules requires modifying validation code inside the class.
  3. Step 3: Side effects

    Because persistence logic shares the class, changes risk affecting persistence unintentionally, increasing maintenance risk.
  4. Step 4: SRP violation

    This coupling violates SRP, as one reason to change (validation) affects unrelated functionality (persistence).
  5. Final Answer:

    Option B -> Option B
  6. Quick Check:

    One reason to change should not force changes in unrelated code -> SRP violation.
Hint: One reason to change means one place to modify.
Common Mistakes:
  • Assuming changes affect only related methods without side effects.
  • Believing tight coupling is harmless if code is in one class.
  • Thinking validation and persistence are always linked.