Lesson 64Classes

Overriding

What is Overriding?

Overriding allows a subclass to provide its own implementation of a method, property, or subscript that it inherits from its superclass. Use the override keyword!

Override Syntax

override func methodName() {
    super.methodName()  // Optional
    // Your implementation
}

What Can Be Overridden

Methods

Instance and type methods

Properties

Computed properties (getters/setters)

Property Observers

Add willSet/didSet to inherited properties

Subscripts

Custom subscript implementations

Preventing Override

Use final to prevent overriding:

  • final func - Method cannot be overridden
  • final var - Property cannot be overridden
  • final class - Entire class cannot be inherited
main.swift
// OVERRIDING
// Subclasses can override inherited methods and properties

// OVERRIDING METHODS
class Animal {
    var name: String

    init(name: String) {
        self.name = name
    }

    func makeSound() {
        print("Some generic sound")
    }

    func describe() {
        print("I am an animal named \(name)")
    }
}

class Dog: Animal {
    override func makeSound() {
        print("Woof! Woof!")
    }

    override func describe() {
        print("I am a dog named \(name)")
    }
}

class Cat: Animal {
    override func makeSound() {
        print("Meow!")
    }
}

let animal = Animal(name: "Generic")
let dog = Dog(name: "Buddy")
let cat = Cat(name: "Whiskers")

animal.makeSound()  // Some generic sound
dog.makeSound()     // Woof! Woof!
cat.makeSound()     // Meow!

// CALLING SUPER METHODS
class Bird: Animal {
    var canFly: Bool

    init(name: String, canFly: Bool) {
        self.canFly = canFly
        super.init(name: name)
    }

    override func describe() {
        super.describe()  // Call parent method first
        print("I \(canFly ? "can" : "cannot") fly")
    }
}

let penguin = Bird(name: "Pingu", canFly: false)
penguin.describe()
// I am an animal named Pingu
// I cannot fly

// OVERRIDING PROPERTIES
class Vehicle {
    var description: String {
        return "A vehicle"
    }

    var maxSpeed: Double {
        return 0
    }
}

class Bicycle: Vehicle {
    override var description: String {
        return "A bicycle"
    }

    override var maxSpeed: Double {
        return 25.0  // km/h
    }
}

class Car: Vehicle {
    override var description: String {
        return "A car"
    }

    override var maxSpeed: Double {
        return 200.0
    }
}

// OVERRIDING WITH PROPERTY OBSERVERS
class SpeedLimitedCar: Car {
    override var maxSpeed: Double {
        didSet {
            if maxSpeed > 120 {
                print("Warning: Speed limited to 120 km/h")
            }
        }
    }
}

// PREVENTING OVERRIDE WITH final
class SecureAnimal {
    final func secureMethod() {
        print("This cannot be overridden")
    }
}

class SecureDog: SecureAnimal {
    // override func secureMethod() { }  // ERROR!
}

// POLYMORPHISM IN ACTION
func animalSound(_ animal: Animal) {
    animal.makeSound()  // Calls the appropriate override!
}

animalSound(dog)  // Woof! Woof!
animalSound(cat)  // Meow!

let animals: [Animal] = [dog, cat, penguin]
for animal in animals {
    animal.makeSound()
}

Try It Yourself!

Create a Shape class with an area() method. Override it in Circle and Rectangle subclasses to return actual areas!