Concepts / Inheritance in Object-Oriented Programming

Inheritance in Object-Oriented Programming

A subclass such as Car inherits the properties and behaviors of its superclass Vehicle.

  • Programming
Interactive lab

Try it: Inheritance and Method Lookup

How a subclass inherits from its parent, how Python finds an attribute by walking the instance, then the class's method resolution order up to object, how overriding and super() work, why the same call does different things on different objects (polymorphism), and what isinstance / issubclass check.

How it works

  1. class Dog(Animal) gives Dog the MRO Dog → Animal → object; Puppy(Dog) gives Puppy → Dog → Animal → object.
  2. obj.name searches obj.__dict__, then each class of type(obj).__mro__ in order; the first class that defines the name wins, so a subclass method overrides the parent's.
  3. super().method() starts the search in the class after the one the current method was defined in, e.g. to run the parent's __init__.
  4. Calling the same method on a list of different objects runs each object's own version (polymorphism).
  5. isinstance(obj, C) is True when C is in type(obj).__mro__; if no class has the name, Python raises AttributeError.

Default run (63 steps): Ready: Animal, Dog, Cat and Puppy, then the statements you picked. Each attribute is searched along the class's MRO. … Finished. Printed: Rex the dog says Woof / Tom the cat says Meow / Bo the dog says Woof! / True / Puppy / Dog / Animal / object.

Simplified: The lab's own small Python interpreter runs a fixed, hand-written script (you choose the variant and the values, never the code); nothing is executed as real Python. Every script was run in CPython 3.12 with the same inputs and the lab reproduces its output and error messages. Single inheritance only (the lab's MRO code is Python's C3 algorithm, but no class here has two parents).

Educational simulation

Loading the simulation…

A Fleet With Shared Details

Suppose you are designing software that tracks a fleet of vehicles. Some vehicles are cars, some are trucks, and some are motorcycles. Each kind has its own details, yet all of them share a great deal: each has a registration number, each has an owner, and each can change hands. Writing those shared details again for every vehicle type would be tedious and error-prone. Object-oriented programming offers a way out, and this article works through a single example to show how it operates.

The question we will follow is practical: if a Car object has been created, what can a program do with it? The answer depends on a rule that connects the Car class to a more general Vehicle class. The programming rule was modeled on something you already know about the physical world, because a car is a kind of vehicle.

What a Car Object Contains

A useful way to read the relationship is that a Car is not built from scratch. It starts with everything a Vehicle has, and then adds what makes it a car. The class Car therefore describes only the additional pieces that distinguish it, while the shared parts live in Vehicle and are available to Car automatically. The same arrangement applies to Truck and Motorcycle, which would also extend Vehicle.

Here is the picture for a single Car object. Its own declared member sits alongside the members it inherits from Vehicle. Each cell below is a member that a program can reach through a car object using the same dot syntax, whether the member was declared in Car or inherited.

numberOfDoorsdeclared in CarregistrationNumberinherited from Vehicleownerinherited from VehicletransferOwnership()inherited from Vehicle
Which fields and methods does a Car object contain, and which of them came from Vehicle versus Car itself?

The source describes this exact situation. It introduces a Car declaration and notes that a program could refer to myCar.numberOfDoors because numberOfDoors is an instance variable declared in class Car. Because Car extends Vehicle, the same car object also gives access to myCar.registrationNumber, myCar.owner, and myCar.transferOwnership(). The first of these is declared by the subclass itself; the other three come from the superclass.

Declaring a Subclass With extends

In a program, a class can be declared so that it extends another class. The class that is extended is called the superclass, and the class doing the extending is called the subclass. In the material this article draws on, Vehicle is the superclass and Car is a subclass of it. The subclass is said to inherit the properties and behaviors of its superclass. Properties are the data a class holds, and behaviors are the actions it can perform.

The source does not show the code of Vehicle, so the following is an illustrative version written to match the member names the source uses. The Java syntax is one way to express the relationship; the idea itself is the same in any object-oriented language.

Code walkthrough
class Vehicle {
    String registrationNumber;
    String owner;

    void transferOwnership(String newOwner) {
        this.owner = newOwner;
    }
}

class Car extends Vehicle {
    int numberOfDoors;
}
  1. 1
    Vehicle declares the two shared fields, registrationNumber and owner, plus the shared method transferOwnership.
  2. 2
    The line class Car extends Vehicle tells the language that Car receives everything Vehicle has.
  3. 3
    Car declares just one new field. It does not repeat registrationNumber, owner, or transferOwnership, because they are already part of Car through the extends relationship.
  • Vehicle is the superclass: it holds the shared data and behavior
  • extends Vehicle is what makes Car a subclass and triggers inheritance
  • Car adds only numberOfDoors, the detail specific to a car
java
Notes on the code
  • numberOfDoors is declared in Car
  • registrationNumber is inherited from Vehicle
  • transferOwnership is an inherited method, called through the car object

What do you think happens?

Given the Vehicle and Car classes above, does the line myCar.transferOwnership("Lee") compile even though Car itself never declares that method?

  • Yes, because Car receives transferOwnership from Vehicle

  • No, because only methods declared inside Car can be called on a Car object

Reveal answer
Answer:

Yes, because Car receives transferOwnership from Vehicle

Car extends Vehicle, so the method is part of a Car object even though the Car class does not write it out. The program can call it through the car object just like a method Car declares itself.

A Car Is Also a Vehicle

The source makes a point that goes beyond access to members. In the real world, cars, trucks, and motorcycles are vehicles. The programming model follows the same logic: an object of type Car or Truck or Motorcycle is automatically an object of type Vehicle too. This is why the inheritance relationship matters for how objects are classified and handled. A Car can be used anywhere the program expects a Vehicle.

Being a Vehicle is not the same as having every member of a Car. The type of the variable that holds the object decides which members the program may name through that variable. If a variable is declared with the type Vehicle, the program is looking at the object through the Vehicle lens. It can use what Vehicle declares, but the Car-specific parts are not part of that view, even though the object contains them.

java
Notes on the code
  • Assigning a Car to a Vehicle variable is allowed because a Car is a Vehicle
  • Vehicle-declared members can be used through v
  • The commented line would fail to compile, because the declared type Vehicle does not include numberOfDoors
What you can doThrough a Car variableThrough a Vehicle variable
Use registrationNumber and ownerYesYes
Call transferOwnership()YesYes
Use numberOfDoorsYesNo, not part of the Vehicle view

The same object, viewed through two different declared types. The object contains numberOfDoors either way; only the variable's type limits what the program may name.

How a Hierarchy Organizes Related Classes

A class hierarchy gives a program a place to express common properties once at a broader level and specific differences at narrower levels. Vehicle sits at the top and holds what all vehicles share. Each subclass sits beneath it and holds only what is specific to that subclass. Car, Truck, and Motorcycle all branch from the same superclass, so the hierarchy records both their differences and the fact that they are all vehicles.

Vehicleshared properties andbehaviorsCaradds numberOfDoorsTruckspecific detailsMotorcyclespecific detailsextendsextendsextends
Where do Vehicle, Car, and other related classes sit relative to one another, and how do they branch from a common superclass?

The arrows in the hierarchy point from the superclass to its subclasses, reflecting the direction in which the shared content flows. Reading a hierarchy from top to bottom therefore tells you what each class receives from above. A class lower down has everything from the classes above it, plus what it adds itself.

Reusing, Extending, and Overriding Behavior

Inheritance is not limited to copying a class unchanged. A subclass can use the inherited properties as they are, add new properties of its own, or override an inherited response. Each of these gives the subclass a controlled way to adapt the superclass rather than starting from an unrelated class.

Why Inheritance Saves Work

Inheritance makes classes reusable components, including when an existing class needs only small adaptations. The drawing-program example in the source shows why this matters. Lines, rectangles, ovals, polygons, and curves need separate classes because they describe different kinds of shapes. At the same time, they share an important identity: each is something the program can draw. Inheritance records both facts, what these classes have in common and what makes each one different.

The source's drawing program places a shared relationship at the top of the hierarchy in a class called DrawableObject, and it groups shapes by the data they need in classes called MultipointObject and TwoPointObject. The hierarchy therefore organizes related classes by common properties instead of treating every class as unrelated. Shared details are written once at the broadest level, and each narrower class contributes only its differences.

Returning to the fleet from the start of this article, the same logic applies. Putting registrationNumber, owner, and transferOwnership in Vehicle means they are written once, not copied into Car, Truck, and Motorcycle. A change to how ownership transfers then happens in one place and reaches every vehicle type that inherits it.

Mistakes Beginners Make With Inheritance

  • Common mistake

    Copying the shared fields and methods into Car instead of inheriting them

    What it looks like

    Writing registrationNumber and owner again inside class Car, alongside extends Vehicle.

    Why it fails

    The shared members already come from Vehicle. Repeating them duplicates code and risks the two copies drifting apart.

    Do this instead

    Declare shared members once in Vehicle and let Car add only what is specific to it.

  • Common mistake

    Assuming a variable can use every member of the object it refers to

    What it looks like

    Holding myCar in a Vehicle variable v and then writing v.numberOfDoors.

    Why it fails

    The declared type of v is Vehicle, so the program may only name members in the Vehicle view, even though the object contains numberOfDoors.

    Do this instead

    Use a Car-typed variable when you need Car-specific members, or cast deliberately if the design requires it.

  • Common mistake

    Believing an override deletes the superclass version

    What it looks like

    Redefining describe in Car and then expecting Vehicle's describe to disappear.

    Why it fails

    Overriding replaces the inherited response for car objects. The superclass definition still exists for the superclass itself.

    Do this instead

    Think of the override as the subclass's own answer to the same message, not as a removal of the superclass.

  • Common mistake

    Thinking inheritance only means copying code, when it also records that a Car is a Vehicle

Tracing a Truck Through the Hierarchy

EASY

Assume Vehicle declares registrationNumber, owner, and transferOwnership, and that Truck extends Vehicle and declares only one new field, loadCapacity. Without looking back, list every member you can reach through a Truck object named myTruck, and state which ones were declared in Truck and which were inherited. Then say whether myTruck.loadCapacity is available if myTruck is held in a Vehicle variable.

Hints
  • Start with the members Truck declares itself, then add everything Truck inherits from Vehicle.
  • Remember that the declared type of the variable limits which members you may name through it, even when the object contains more.
MEDIUM

Sketch a small hierarchy for a drawing program with a shared superclass and two subclasses. Name one member the superclass declares, one member each subclass adds, and one response a subclass overrides. Label which members are declared versus inherited.

Hints
  • Use the source's idea that shared identity goes at the top and differences go at the bottom.
  • An override only applies to a message the superclass already responds to.

Putting the Pieces Together

The example reduces to a few connected ideas. A subclass such as Car extends a superclass such as Vehicle and thereby receives its structure and behavior. A program can reach both the members a subclass declares and the members it inherits, using the same dot syntax. An object of a subclass is also an object of its superclass, which is why the relationship reflects the real-world fact that cars are vehicles. Finally, the declared type of the variable that holds the object limits which members the program may name through that variable.

Key Takeaways

  • A subclass such as Car extends a superclass such as Vehicle and inherits its properties and behaviors, so the shared parts are written once in Vehicle.
  • A Car object reaches both its own declared members, such as numberOfDoors, and inherited members, such as registrationNumber and transferOwnership(), with the same dot syntax.
  • A Car is also a Vehicle, but the declared type of a variable limits which members the program may name through it, even though the object contains more.
  • A subclass can reuse inherited members, extend them with new ones, or override an inherited response with its own version.
  • Inheritance organizes related classes into a hierarchy and supports reuse by recording shared identity at the top and specific differences below.