Chapter 13

Object-Oriented Programming

High School
At a glance
Core ideaObjects bundle data with the behaviour that acts on it.
Key termPolymorphism — one interface, many runtime implementations.
You can…Model a domain with classes, inheritance and encapsulation.
Watch outPrefer composition over deep, brittle inheritance trees.
Theory

Object-oriented programming (OOP) organises software around objects — bundles of data (attributes/state) and the behaviour (methods) that acts on it. A class is a blueprint; an object is an instance of that class. OOP rests on four pillars:

  • Encapsulation — bundle data with the methods that manage it, and hide internal detail behind a public interface. The outside world uses the object without depending on how it works inside.
  • Abstraction — expose what an object does, conceal how. A BankAccount exposes withdraw(), not the ledger internals.
  • Inheritance — a subclass reuses and extends a parent class, modelling an "is-a" relationship (a Dog is an Animal).
  • Polymorphism — one interface, many implementations: calling speak() on different animals runs different code, chosen at runtime by the object's actual type.
Explanation

OOP is fundamentally a strategy for managing complexity in large programs. By grouping state with the operations that maintain it, an object can enforce its own invariants — e.g. a bank balance that never goes negative — so no external code can corrupt it. This is encapsulation's real payoff: local reasoning. You can trust an object because it guards itself.

Polymorphism is the pillar that pays dividends at scale. Write code that calls shape.area() and it works for circles, squares, and triangles you have not even written yet — as long as each provides an area(). New types slot in without touching old code. This "open for extension, closed for modification" principle is why OOP dominated large-system design for decades.

Caveat. OOP is a tool, not a religion. Deep inheritance hierarchies often cause more pain than they cure; modern practice favours composition over inheritance — build objects from smaller parts rather than inheriting from towering ancestors.

Practical

We model animals to show all four pillars: a base class, a private-by-convention attribute (encapsulation), two subclasses (inheritance), and a shared method behaving differently (polymorphism).

class Animal:
    def __init__(self, name):
        self._name = name          # leading underscore: "internal, please don't touch"

    def name(self):                # public accessor -> encapsulation
        return self._name

    def speak(self):
        raise NotImplementedError  # abstract: each subclass must define this

class Dog(Animal):                 # Dog IS-A Animal  -> inheritance
    def speak(self):
        return "Woof"

class Cat(Animal):
    def speak(self):
        return "Meow"

class Cow(Animal):
    def speak(self):
        return "Moo"

# Polymorphism: identical call, type-specific behaviour chosen at runtime
animals = [Dog("Rex"), Cat("Milo"), Cow("Daisy")]
for a in animals:
    print(a.name() + " says " + a.speak())

# Output:
# Rex says Woof
# Milo says Meow
# Daisy says Moo

The loop never asks "what kind of animal is this?" — it simply calls speak() and each object supplies its own answer. Add a Duck class tomorrow and the loop works unchanged. That is polymorphism buying you extensibility.

Q&A
Q1 What is the difference between a class and an object?

A class is a template — a definition of what attributes and methods instances will have. An object is a concrete instance created from that template, with its own actual data. Dog is the class; Rex and Fido are two distinct objects, each with its own name, both sharing the speak() behaviour defined once in the class.

Q2 Why hide data behind methods instead of accessing it directly?

Encapsulation lets the object enforce rules. If balance is only changed through deposit() and withdraw(), those methods can reject invalid operations (a negative withdrawal, an overdraft) and maintain invariants. Expose the raw field and any code anywhere can violate them, making bugs impossible to localise.

Q3 What does "composition over inheritance" mean?

Rather than making a Car inherit from Engine, give the car an engine as a component (self.engine = Engine()). Composition ("has-a") is more flexible than inheritance ("is-a"): you can swap parts, mix behaviours, and avoid the brittle, deep hierarchies that make inheritance hard to change. Inheritance is best reserved for genuine "is-a" relationships.

Q4 How does polymorphism actually pick the right method?

Through dynamic dispatch: at runtime, the object carries a reference to its class, and the language looks up speak() on that class (and its ancestors). So the method chosen depends on the object's actual type, not the type of the variable holding it. This late binding is what lets one line of code serve many types.

Concept mind map

How the ideas connect

Every key idea in this chapter, branching from the core concept — use it to see the whole picture at a glance.

classobjectencapsulationinheritancepolymorphismmethodObject-oriented design
Infographic

The key facts, visualised

Class
A blueprint defining data (fields) and behaviour (methods).
Object
A concrete instance created from a class.
Encapsulation
Bundling data with its methods and hiding internal details.
Polymorphism
One interface, many runtime implementations.
Solved examples

Worked problems, step by step

Follow each solution line by line, then try to reproduce it on paper before moving on.

Example 1A class Dog has method speak() returning "Woof". Cat.speak() returns "Meow". You call speak() on an Animal that is a Cat. What is returned?

  1. The variable is typed Animal but holds a Cat.
  2. Polymorphism picks the Cat implementation at runtime.

Example 2Circle inherits Shape and overrides area(). For radius 2, area = 3.14 * r^2. Compute.

  1. area = 3.14 * 2^2.
  2. 3.14 * 4.
Practice problem set

Now you try

Work each one out first, then tap to reveal the worked answer.

1What is the difference between a class and an object?
A class is the blueprint; an object is a concrete instance built from that blueprint.
2What is encapsulation?
Bundling data with the methods that act on it and hiding internal details behind an interface.
3What is inheritance?
A mechanism where a subclass reuses and extends the fields and methods of a parent class.
4What is polymorphism?
The ability to call one interface and get different behaviour depending on the actual object type at runtime.
5What is a method?
A function defined inside a class that operates on the object data.
6Why bundle data with behaviour?
It keeps related logic together, protects invariants, and lets callers use an object without knowing its internals.