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
overrideis an error:overriding declaration requires an 'override' keyword. - Writing
overrideon 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
superwhen 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.finalprevents overriding.
