Skip to content
AgileLogics
5 min read

Inheritance

Prerequisites: Structs vs classes

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

Example

class Vehicle {
    let wheels: Int

    init(wheels: Int) {
        self.wheels = wheels
    }

    func describe() -> String {
        "A vehicle with \(wheels) wheels"
    }
}

class Bicycle: Vehicle {
    init() {
        super.init(wheels: 2)
    }

    override func describe() -> String {
        super.describe() + " that you pedal"
    }
}

final class Car: Vehicle {
    let brand: String

    init(brand: String) {
        self.brand = brand
        super.init(wheels: 4)
    }

    override func describe() -> String {
        "A \(brand) car"
    }
}

let vehicles: [Vehicle] = [Bicycle(), Car(brand: "Volvo")]
for vehicle in vehicles {
    print(vehicle.describe())
}

Expected output

A vehicle with 2 wheels that you pedal
A Volvo car
  • class Bicycle: Vehicle makes Bicycle a subclass of Vehicle.
  • override is required when replacing a superclass method — so you can't override something by accident.
  • super.describe() calls the superclass's version.
  • A subclass initializer sets its own properties first, then calls super.init.
  • An array of Vehicle can hold any subclass, and each element uses its own describe() — this is polymorphism.

final class Car can't be subclassed further.

Inheritance in practice

In your own Swift code, deep class hierarchies are uncommon — sharing behavior through protocols (the Protocols lesson) is usually more flexible and works with structs too. You'll use inheritance most when subclassing framework classes.

Common mistakes

  • Forgetting override: overriding declaration requires an 'override' keyword.
  • Calling super.init before setting the subclass's own properties.