Understanding Inheritance and Polymorphism

Tutorial 4 of 5

1. Introduction

Goal

In this tutorial, we aim to provide you with a comprehensive understanding of inheritance and polymorphism in Swift. These are fundamental concepts in object-oriented programming (OOP) that not only allow you to write more efficient code but also promote the reusability of your code.

Learning Outcomes

By the end of this tutorial, you will be able to:

  • Understand the concepts of inheritance and polymorphism.
  • Apply inheritance to create subclasses and superclasses.
  • Use polymorphism to design flexible and reusable code.
  • Implement these concepts in Swift programming.

Prerequisites

To get the most out of this tutorial, you should have a basic understanding of Swift programming and its syntax. Familiarity with object-oriented programming concepts will be beneficial but not required.

2. Step-by-Step Guide

Inheritance

Inheritance is a fundamental concept in OOP where a class can inherit properties and behaviors from another class, often referred to as the parent class or superclass.

class Animal {
    var name: String
    func speak() { }

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

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

In this example, Dog is a subclass of Animal and it inherits the name property and the speak() method from Animal. The override keyword is used to provide a new implementation of a method that is already defined in the superclass.

Polymorphism

Polymorphism is another fundamental concept in OOP that allows one type to appear as and be used like another type. In Swift, there are two types of polymorphism: subtype polymorphism and parametric polymorphism.

let dog: Animal = Dog(name: "Rex")
dog.speak() // prints "Woof!"

In this example, although dog is declared as type Animal, it's actually an instance of Dog. When we call dog.speak(), it prints "Woof!", which shows subtype polymorphism in action.

3. Code Examples

Inheritance

Here's an example of a Car class that has two subclasses, ElectricCar and GasCar.

class Car {
    var make: String
    var model: String

    init(make: String, model: String) {
        self.make = make
        self.model = model
    }

    func drive() {
        print("Driving a \(make) \(model).")
    }
}

class ElectricCar: Car {
    override func drive() {
        print("Driving a \(make) \(model), it's electric!")
    }
}

class GasCar: Car {
    override func drive() {
       print("Driving a \(make) \(model), it's gas-powered!")
    }
}

let tesla = ElectricCar(make: "Tesla", model: "Model S")
tesla.drive() // prints "Driving a Tesla Model S, it's electric!"

let ford = GasCar(make: "Ford", model: "F-150")
ford.drive() // prints "Driving a Ford F-150, it's gas-powered!"

4. Summary

We've covered:

  • The concepts of inheritance and polymorphism in Swift.
  • How to create subclasses and superclasses using inheritance.
  • How to use polymorphism to design flexible and reusable code.

To continue your learning journey, practice these concepts with more complex examples. You can also learn about other OOP concepts like encapsulation and abstraction. Check out the Swift documentation for more information.

5. Practice Exercises

  1. Create a Bird class with a fly() method. Then create Eagle and Penguin subclasses that override the fly() method. Eagles can fly but penguins cannot.

  2. Implement polymorphism with a Shape class and its subclasses Circle and Rectangle. Each shape should have an area method that calculates its area.

Try to solve these on your own before looking at the solutions below.

Solutions

  1. Bird classes:
class Bird {
    var name: String
    func fly() { }

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

class Eagle: Bird {
    override func fly() {
        print("\(name) is flying high!")
    }
}

class Penguin: Bird {
    override func fly() {
        print("\(name) can't fly.")
    }
}
  1. Shape classes:
class Shape {
    func area() -> Double {
        return 0
    }
}

class Circle: Shape {
    var radius: Double

    init(radius: Double) {
        self.radius = radius
    }

    override func area() -> Double {
        return Double.pi * radius * radius
    }
}

class Rectangle: Shape {
    var width: Double
    var height: Double

    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }

    override func area() -> Double {
        return width * height
    }
}