Inheritance

A subclass takes the fields and methods of its parent and adds or replaces some. It is the right tool for a true is-a relationship and the wrong one for sharing code.

Overview

Inheritance lets one class (the subclass) be defined in terms of another (the superclass). The subclass starts with the parent's members and can add new ones or override the ones it inherits. A SavingsAccount is an Account with an interest rate; a CheckingAccount is an Account with an overdraft limit. Code written for Account works on both.

Interviewers use inheritance questions to check two things. First, that you know the mechanics: what is inherited, what overriding means, how a call is resolved. Second, and more important, that you know when not to use it. Most inheritance in real codebases is there to reuse code, not to model an is-a relationship, and that is where the fragile hierarchies come from.

A subclass is a special case of its parent

What exactly comes down the arrow is language-specific, and Java's rules are the ones interviewers expect you to know.

  • public and protected members — yes, whatever package the subclass is in
  • package-private members — only if the subclass is in the same package
  • private members — no; the subclass can reach them only through the parent's methods
  • constructors — no; the subclass calls one with super(...)
  • static members — yes, but a static method with the same signature hides, it does not override

Every Java class except Object has exactly one direct superclass. Python and C++ allow several, which is covered below.

Override, do not hide

Overriding is a subclass providing its own version of an instance method it inherited, with the same signature. When the method is called through a variable of the parent type, the runtime picks the version that matches the object's actual class. The Java tutorial states it plainly: the JVM calls the method for the object referred to, not the method defined by the variable's type. That is the mechanism behind polymorphism.

Two other things look like overriding and are not.

  • Same signature, instance method — overriding — at run time, by the object's class — mark it @Override; the compiler errors if nothing matches
  • Same name, different parameters — overloading — at compile time, by the argument types — unrelated to inheritance
  • Same signature, both static — hiding — at compile time, by the variable's type — avoid; it confuses readers
  • Instance in one, static in the other — not allowed — compile-time error

Composition or inheritance

The Gang of Four's 1994 book put it as a principle: favor object composition over class inheritance. Inheritance is the right tool when three things are all true. If any is false, give the class a field of the other type and delegate.

  • Relationship — is a — has a, uses a
  • Bound — at compile time, fixed — at run time, swappable
  • Coupling — the subclass sees and depends on the parent's internals — the owner sees only the part's public interface
  • Change in the base — ripples into every subclass — contained behind the interface
  • Combining behaviors — one axis per hierarchy; two axes multiply classes — one field per axis

Multiple inheritance and the diamond

A diamond is a class that inherits the same ancestor by two paths. The question is which copy of the ancestor's data you get and which version of an overridden method runs. Languages answer it differently, and the interview point is to know each answer.

  • Java — no: one superclass, many interfaces — cannot happen with classes; colliding default methods must be overridden
  • C++ — yes — the shared base appears twice unless each path inherits it as virtual, in which case there is one subobject
  • Python — yes — one copy; method lookup follows the C3 linearization (the MRO), which keeps each class's base order and puts every class before its parents

The super() chain visits each class once, in MRO order, so Python's answer to the diamond is cooperative: each class calls the next, and no class needs to know which class that is.

What you will be able to do

  • Say precisely what a subclass inherits and what it does not, in Java and in Python.
  • Tell overriding, overloading and hiding apart, and say when each is resolved.
  • Decide between inheritance and composition with a reason the interviewer will accept.
  • Explain the diamond problem and how Java, C++ and Python each handle it.
  • State the Liskov substitution rule and spot a hierarchy that breaks it.

Interview questions

  • What is the difference between overriding and overloading?
  • When should you prefer composition over inheritance?
  • What does the Liskov substitution principle require of a subclass?
  • How do access modifiers interact with inheritance?
  • How do you stop a class from being extended, and why would you?
  • How does Python decide which method runs with multiple inheritance?

Sign up free to read the full topic

More Low-Level Design topics

Start free on Cariara · Coding problems · System design studio