B3.2.1 Explain and apply the concept of inheritance in OOP to promote code reusability. (HL only)

B3.2.1 Explain and apply the concept of inheritance in OOP to promote code reusability. 
• How inheritance enables a hierarchical relationship between parent and child classes 
• Extending existing classes, utilizing inheritance to reuse and extend functionalities 
• The impact of inheritance on access to parent class members with different access modifiers (private, public, protected, default)

The big idea

Inheritance in object-oriented programming allows one class (child/subclass) to reuse and extend the attributes and methods of another class (parent/superclass).

It creates a hierarchical relationship — much like real-world categories:

  • Vehicle (parent)
    • Car (child)
    • Motorbike (child)

This hierarchy promotes code reusability, reduces duplication, and makes programs easier to maintain.

 

1. Hierarchical relationship

In Python, a child class inherits from a parent by specifying the parent in parentheses:

class Vehicle:
    def __init__(self, brand):
        self.brand = brand
    def start(self):
        return f"{self.brand} vehicle starting..."
class Car(Vehicle):
    def honk(self):
        return "Beep beep!"
my_car = Car("Toyota")
print(my_car.start())  # Inherited from Vehicle
print(my_car.honk())   # Defined in Car

Key point:

  • Car automatically has access to start() from Vehicle.
  • We didn’t have to rewrite start() in Car.

 

2. Extending existing classes

A child class can:

  • Use all public and protected members from the parent.
  • Add new methods and attributes.
  • Override existing methods to change behavior.
class ElectricCar(Car):
    def __init__(self, brand, battery_capacity):
        super().__init__(brand)  # Call parent constructor
        self.battery_capacity = battery_capacity
    # Override start method
    def start(self):
        return f"{self.brand} electric car silently starting..."
    def charge(self):
        return f"Charging to {self.battery_capacity} kWh."
tesla = ElectricCar("Tesla", 75)
print(tesla.start())   # Overridden method
print(tesla.honk())    # From Car
print(tesla.charge())  # Unique to ElectricCar

 

3. Access modifiers in Python

Python does not enforce access modifiers as strictly as Java or C++, but uses naming conventions and name mangling:

Access TypeSyntaxMeaning
Publicself.nameAccessible everywhere
Protectedself._nameIntended for internal or subclass use only (not enforced)
Privateself.__nameName-mangled to prevent accidental access (still accessible if forced)

Example:

class Account:
    def __init__(self, owner, balance):
        self.owner = owner         # public
        self._account_type = "Savings"  # protected
        self.__balance = balance   # private

    def deposit(self, amount):
        self.__balance += amount
        return f"New balance: {self.__balance}"

    def get_balance(self):
        return self.__balance

class PremiumAccount(Account):
    def upgrade(self):
        # Can access public and protected members
        self._account_type = "Premium"
        # Cannot directly access __balance (private)
        # self.__balance = 0  # Would cause AttributeError
        return f"Upgraded {self.owner} to {self._account_type}"

acct = PremiumAccount("Alice", 1000)
print(acct.upgrade())
print(acct.get_balance())  # Uses a public method to access private data

 

Why inheritance matters for reusability

  • Without inheritance: Each class must define its own duplicate logic.
  • With inheritance: Shared logic lives in the parent; children only add or customize.
  • Result: Smaller codebase, fewer bugs, easier updates.

Example:
If you add logging to the start() method in Vehicle, all subclasses automatically get the updated behavior without changing their own code.

 

Best practices

  • Use inheritance for is-a relationships (e.g., Car is a Vehicle).
  • Avoid deep inheritance chains — they can be hard to follow.
  • Combine inheritance with composition where appropriate.
  • Clearly document which methods are safe for subclasses to override.