Skip to content
AgileLogics
6 min read

Inheritance

Prerequisites: Classes and objects

Inheritance lets a class build on another class. The subclass gets the superclass's properties and methods and can add or change behavior.

In Kotlin, classes are final by default — they can't be inherited from unless marked open. This is deliberate: designing a class for inheritance takes care, so you opt in explicitly.

Example

open class Vehicle(val wheels: Int) {
    open fun describe() = "A vehicle with $wheels wheels"
}

class Bicycle : Vehicle(2) {
    override fun describe() = super.describe() + " that you pedal"
}

class Car(val brand: String) : Vehicle(4) {
    override fun describe() = "A $brand car"
}

fun main() {
    val vehicles: List<Vehicle> = listOf(Bicycle(), Car("Volvo"))
    for (vehicle in vehicles) {
        println(vehicle.describe())
    }
}

Expected output

A vehicle with 2 wheels that you pedal
A Volvo car
  • open class allows subclasses; open fun allows overriding.
  • class Bicycle : Vehicle(2) inherits from Vehicle, passing 2 to its constructor.
  • override is required when replacing a method, so you can't override something by accident.
  • super.describe() calls the superclass's version.
  • A List<Vehicle> can hold any subclass, and each element uses its own describe() — this is polymorphism.

Abstract classes

An abstract class can't be created directly; it exists to be subclassed, and can declare methods that subclasses must implement:

abstract class Shape {
    abstract fun area(): Double
    fun describe() = "Area: ${"%.2f".format(area())}"
}

class Square(val side: Double) : Shape() {
    override fun area() = side * side
}

class Circle(val radius: Double) : Shape() {
    override fun area() = Math.PI * radius * radius
}

fun main() {
    println(Square(3.0).describe())
    println(Circle(1.0).describe())
}
Area: 9.00
Area: 3.14

Prefer composition and interfaces

Deep inheritance chains become hard to follow and change. Kotlin code usually shares behavior through interfaces (next lesson) and by having one object hold another (composition), keeping inheritance for true "is a kind of" relationships.

Common mistakes

  • Forgetting open: This type is final, so it cannot be extended.
  • Forgetting override: the compiler reports that the method hides a member of the superclass and needs the override modifier.