Concepts / Method Overriding in Subclasses

Method Overriding in Subclasses

The method that executes is determined at runtime from the actual object type, not from the parent type used to refer to the object.

  • Programming

One Group, Many Roles

Imagine counting everyone in a school building. You could write separate logic for teachers, students, and administrators. Polymorphism offers another approach: treat each person as a SchoolMember while allowing each subtype to keep its specialized behavior. The code works with the shared parent type instead of needing to know every concrete subtype.

Definition

Polymorphism allows a subtype to be treated as an instance of its parent type. This enables flexible code that works with multiple subtypes without type checking.

SchoolMemberTeacherStudentSchoolMembercollectionparent type ofparent type ofcan containcan contain
How can objects from different subclasses be treated uniformly as instances of their shared parent type?

The Parent-Type View

A subtype is a specialized form of its parent type. A Teacher object can therefore be used anywhere a SchoolMember is expected, and a Student object can be treated in the same general way. The code using the object does not need to care which specific subtype it received. It can rely on the behavior and functionality associated with the parent type.

Key point

Polymorphism separates what the calling code needs to know from how each subtype performs its behavior. The calling code uses the shared parent-type interface; the actual object supplies the specialized implementation.

This makes one piece of code reusable across multiple subtypes. Instead of creating separate functions for teachers and students, you can write one operation that works with SchoolMember objects. When a new subtype is added, that existing operation can continue working without modification.

Finding the Overridden Method

Suppose SchoolMember provides a tell() method, and Teacher and Student each provide their own version. A variable can be treated as a SchoolMember reference while actually holding a Teacher object. When tell() is called, the Teacher version runs. If the object is a Student, the Student version runs instead.

This selection is dynamic dispatch. The method that executes is determined at runtime from the actual object type, not from the parent type used to refer to the object. The decision happens each time the method is called, so one collection of SchoolMember references can contain different subtypes and still invoke the correct implementation for each object.

SchoolMemberreferenceActual objecttell()Teacher tell()Student tell()refers toreceivesTeacher objectStudent object
When code calls a method through a parent-type reference, how does control reach the correct subclass implementation?

A SchoolMember Collection

Worked example

Counting and Notifying School Members

A school needs to process teachers and students together. How can it use one parent-type view while preserving each subtype's behavior?

  1. 1
    Gather the objects

    Place Teacher and Student objects in a collection viewed as containing SchoolMember references.

  2. 2
    Use the shared type

    The processing logic handles each object as a SchoolMember instead of branching on whether it is a Teacher or a Student.

  3. 3
    Call shared behavior

    When the logic calls tell(), dynamic dispatch examines the actual object and selects the matching subtype implementation.

  4. 4
    Add another subtype

    A new SchoolMember subtype can participate in the same processing approach without requiring the existing processing logic to change.

Result

One operation can work with multiple SchoolMember subtypes uniformly, while each object retains its own implementation of overridden behavior.

Member processorTeacherStudentTeacher behaviorStudent behaviorprocesses as SchoolMemberprocesses as SchoolMemberdispatches todispatches to
How does one operation process multiple subtypes through one parent-type interface without branching on each concrete type?

The important design choice is that the processing logic depends on SchoolMember rather than on a list of concrete subtype checks. The objects are handled through the same parent-type view, but dynamic dispatch preserves the correct behavior for each actual object.

Inherited Functionality

Inheritance works in the other direction when functionality is added to the parent. If a new ID card field is added to SchoolMember, both Teacher and Student objects automatically have access to it. The same propagation applies to new parent-class methods. Subtypes inherit the parent class's attributes and methods without requiring each subtype to be modified separately.

SchoolMemberID card fieldTeacherID card fieldStudentID card fieldinherited byinherited by
What functionality is added to every subtype when a new method or field is added to the parent class?

Isolated Subtype Changes

Changes made inside one subtype remain isolated. If a new method is added only to Teacher, that method does not appear in Student and does not modify SchoolMember. Likewise, changing how Teacher behaves does not change the behavior of Student or the parent class.

SchoolMemberoriginal behaviorTeacheroriginal behaviorSchoolMemberoriginal behaviorTeacheroverridden behaviorStudentoriginal behaviorStudentoriginal behaviorparent ofparent ofparent ofparent of
When one subtype overrides or changes a method, which classes and objects are affected, and which remain unchanged?
Key point

Subtype isolation makes maintenance safer: changing one subtype's behavior does not accidentally change the parent class or the behavior of sibling subtypes.

Mistakes About Overriding

  • Common mistake

    Assuming the parent-type reference determines which method runs.

    What it looks like

    A SchoolMember reference holds a Teacher object, and the caller expects the generic SchoolMember implementation to run.

    Why it fails

    Dynamic dispatch selects the method from the actual runtime object type, so the Teacher implementation runs.

    Do this instead

    Separate the reference type from the actual object type when reasoning about an overridden method call.

  • Common mistake

    Assuming a method added to one subtype becomes available in every subtype.

    What it looks like

    A method added only to Teacher is expected to appear in Student.

    Why it fails

    Changes made in a subtype remain isolated and do not affect sibling subtypes or the parent class.

    Do this instead

    Place functionality in the parent when every subtype should inherit it; place it in one subtype when it should remain specialized.

  • Common mistake

    Writing separate processing logic for every known subtype.

    What it looks like

    A school-processing operation handles Teacher objects and Student objects through separate branches even though both are SchoolMembers.

    Why it fails

    Polymorphism is intended to let one operation work with multiple subtypes through their shared parent type without type checking.

    Do this instead

    Use the parent type for the shared operation and allow dynamic dispatch to select subtype-specific behavior.

  • Common mistake

    Assuming a parent-class change must be repeated manually in every subtype.

    What it looks like

    An ID card field is added to SchoolMember, but each subtype is treated as though it must define the field again.

    Why it fails

    Functionality added to the parent class automatically propagates to its subtypes.

    Do this instead

    Reason from the inheritance relationship: inherited parent attributes and methods become available to the subtypes.

Practice the Dispatch

MEDIUM

A collection is viewed as containing SchoolMember objects. It contains one Teacher and one Student, and both subtypes provide their own tell() implementation. Describe what happens when the same processing operation calls tell() for each object. Then explain what would happen if a new field were added to SchoolMember and a separate method were added only to Teacher.

Hints
  • Track the actual object type for each collection item.
  • Remember that dynamic dispatch chooses the implementation at runtime.
  • Distinguish functionality added to the parent from functionality added to one subtype.

What do you think happens?

A parent-type reference holds a Teacher object. Which tell() implementation does a call through that reference use?

  • The SchoolMember implementation because the reference uses the parent type

  • The Teacher implementation because the actual object is a Teacher

  • No implementation because a subtype cannot be treated as its parent

Reveal answer
Answer:

The Teacher implementation because the actual object is a Teacher.

Dynamic dispatch selects the correct subtype method at runtime based on the actual object type, not the reference type.

Designing for Extension

Polymorphism supports the Open-Closed Principle. Code using the parent type is open for extension because new subtypes can be added, but closed for modification because the existing code does not need to change for each new subtype. This design also improves maintainability: subtype-specific behavior can be changed in the subtype while the parent class and other subtypes remain unaffected.

Key Takeaways

  1. 1
    Polymorphism lets a subtype be treated as an instance of its parent type.
  2. 2
    Dynamic dispatch chooses the overridden method at runtime from the actual object type.
  3. 3
    Functionality added to a parent class automatically becomes available to its subtypes.
  4. 4
    Changes made in one subtype remain isolated from sibling subtypes and the parent class.
  5. 5
    Parent-type processing supports flexible code that can accept multiple subtypes without type checking.

At a glance

  • Polymorphism allows objects of different subtypes to be handled through a shared parent-type view.
  • Dynamic dispatch sends a method call to the correct subtype implementation at runtime.
  • Parent-class functionality propagates automatically to all subtypes.
  • Subtype-specific changes remain isolated and do not alter sibling subtypes or the parent.
  • This combination enables flexible code that is open for extension and closed for modification.

Related concepts

More concepts starting with M