Start learning free

LESSON 405 OF 415 · OBJECT-ORIENTED PROGRAMMING

Method Overriding in Swift: override and super

Lesson Read the full explanation

TL ; DR:

When a child class defines a method with the same name as the parent's, the child's version overrides the parent's. Different objects can give the same method name different behavior.


class Dog {
    func bark() { print("Woof!") }
}
class Puppy: Dog {
    override func bark() { print("Yip!") }
}


Full lesson:

You've seen that a child class inherits the parent's methods. Overriding is what happens when the child wants to change one of those inherited methods.

Why override?

Subclasses are usually special cases of the parent. A Puppy is a Dog, but it sounds different — "Yip!" instead of "Woof!". Instead of inventing a new method name, you redefine bark() on the Puppy. Callers don't need to know which subclass they're holding — they just call bark() and the right version runs.

How it works in Swift

  • The parent method needs no special marking; any non-final method of a class can be overridden.
  • The child marks its replacement with the override keyword, which is required: without it the compiler reports an error.
  • The child's method must have the same name and parameter types as the parent's.
  • Mark a method final in the parent to forbid overriding it.

Your task

The Dog class already defines bark. Inside the Puppy subclass, override bark so it prints "Yip! I am " followed by the puppy's name. The harness creates a Puppy named "Buddy" and calls bark() on it.

Expected output:

Yip! I am Buddy
STEP 1 OF 2
    Ctrl + Enter to check

    SWIFT · OBJECT-ORIENTED PROGRAMMING

    Method Overriding in Swift, explained

    Why override

    A subclass often behaves a little differently from its parent. A puppy is a dog but yips instead of woofing. Rather than inventing a new method name, the subclass redefines the inherited method. Code that calls bark() doesn't need to know which kind of dog it holds; the right version runs.

    The override keyword

    In Swift, a method that replaces an inherited one must be marked override:

    class Dog {
        func bark() { print("Woof!") }
    }
    
    class Puppy: Dog {
        override func bark() { print("Yip!") }
    }
    

    The parent's func bark() needs no special mark to be overridable. The keyword is required on the child, and the compiler checks it in both directions:

    • Writing the same method without override is an error: overriding declaration requires an 'override' keyword.
    • Writing override on a method the parent doesn't have is an error too: method does not override any method from its superclass. This catches typos in names.

    The parent can forbid overriding with final: overriding a final func gives instance method overrides a 'final' instance method.

    Which version runs

    The version is chosen by the actual type of the object, not by the type of the variable holding it:

    class Dog {
        var name: String
        init(_ name: String) { self.name = name }
        func bark() { print("Woof! I am \(name)") }
    }
    
    class Puppy: Dog {
        override func bark() { print("Yip! I am \(name)") }
    }
    
    let dogs: [Dog] = [Dog("Max"), Puppy("Buddy")]
    for d in dogs { d.bark() }
    

    The array's element type is Dog, yet the output is Woof! I am Max followed by Yip! I am Buddy. This behavior is called polymorphism.

    Calling the parent version

    An override can extend the original instead of replacing it by calling super.bark():

    class Loud: Dog {
        override func bark() {
            super.bark()
            print("LOUD")
        }
    }
    

    Loud("L").bark() prints Woof! I am L and then LOUD.

    The exercise

    The starter Puppy has an empty body. It needs no initializer, because it inherits Dog's, which is why Puppy("Buddy") compiles. Add the override inside Puppy, first as an empty method and then printing the text:

    class Dog {
        var name: String
        init(_ name: String) { self.name = name }
        func bark() {
            print("Woof! I am \(name)")
        }
    }
    
    class Puppy: Dog {
        override func bark() {
            print("Yip! I am \(name)")
        }
    }
    
    class Solution {
        func mainFunction() {
            let buddy = Puppy("Buddy")
            buddy.bark()
        }
    }
    

    The output is Yip! I am Buddy. The property name is inherited, so the override reads it without any qualifier.

    Overriding versus overloading

    These two words sound alike but mean different things. Overriding replaces an inherited method with the same name and the same parameters. Overloading defines several methods with the same name but different parameters, in one class or across a hierarchy. If a subclass declares func bark(times: Int) next to the inherited func bark(), it has added a second method, so it doesn't need, and can't use, the override keyword.

    Here Puppy ends up with both bark(), inherited unchanged and printing Woof!, and bark(times:), its own. Calling bark() on a puppy runs the parent's version, and bark(times: 2) prints Yip! twice.

    When to use it

    Override when a subclass has a real reason to behave differently for the same request: the caller asks a dog to bark, and each kind of dog answers in its own way. Keep the meaning of the method the same in every subclass. If an override does something unrelated to the original, code that relies on the parent's behavior will be surprised. And if most of the original behavior is still wanted, call super and add to it instead of copying the parent's code into the child.

    Common mistakes

    • Forgetting override. Swift refuses to compile it.
    • Changing the signature. A method with the same name but different parameters is a separate method, an overload, not an override.
    • Overriding a method that doesn't exist, for example by misspelling the name.
    • Not calling super when the parent's behavior is still wanted.

    Key takeaways

    • A subclass replaces an inherited method by redeclaring it with override.
    • The compiler checks that something is really being overridden.
    • The object's real type decides which version runs.
    • super.method() calls the parent's version.
    • final prevents overriding.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free