Наследование

Давайте разберемся с наследованием на примере

class Person {
    var firstName: String
    var lastName: String
    init(firstName:String, lastName:String) {
         self.firstName = firstName
         self.lastName = lastName
    }
}
class Student {
    var firstName: String
    var lastName: String
    var course: String
    init(firstName:String, lastName:String) {
         self.firstName = firstName
         self.lastName = lastName
    }
}

Мы видим, что между человеком и учеником существует много дублирования кода, это показывает нам, что между учеником и человеком есть отношения, т.е. ученик - это человек. Наследование помогает представить этот вид отношение.

Класс может наследовать методы, свойства и другие характеристики от другого класса. Когда один класс наследуется от другого, наследующий класс известен как подкласс, а класс, от которого он наследуется, известен как его суперкласс .

Давайте перепишем приведенный выше пример, используя наследование

class Person { .  // base class or super class
    var firstName: String
    var lastName: String
    init(firstName:String, lastName:String) {
         self.firstName = firstName
         self.lastName = lastName
    
    }
}
class Student : Person { // subclass
    var course: String
    init(firstName:String, lastName:String , course: String) {
         self.course = course
         super.init(firstName: firstName, lastName: lastName)
    }
}

Теперь класс Student наследуется от Person, через наследование студент автоматически получает свойства и метод, объявленные в классе Person. Кроме того, объект Student будет иметь все свойства, определенные в подклассе, то есть курс является свойством экземпляра Student, а не Person.

Быстрый класс может наследовать только от одного класса, который известен как одиночное наследование, но нет ограничений на глубину создания подклассов.

Полиморфизм

Поскольку классы поддерживают наследование, они привносят новую функцию, известную как полиморфизм, то есть способность объекта принимать различные формы.

Давайте разберемся с этим на примере

class Person { // base class
   var name: String
   init(name: String) {
       self.name = name
    }
   func getInformation() -> String {
       return "My name is \(name) "
    }
}
class Employee : Person {
   var employer: String
   init(name: String, employer: String) {
       self.employer = employer
       super.init(name: name)
   }
   override func getInformation() -> String {
       return "My name is \(name) and work for \(employer)"
   }
}
class Student : Person {
   var college: String
   init(name: String, college: String) {
        self.college = college
        super.init(name: name)
   }
   override func getInformation() -> String {
        return "My name is \(name) and study at \(college)"
   }
}

В приведенном выше примере студент и сотрудник наследуют от человека. Из-за этого любой экземпляр этих двух классов содержит все свойства Person, а экземпляр Student / Employee также может рассматриваться как экземпляр Person.

var john = Employee(name: "John", employer: "ABC")
var shiva = Student(name: "Shiva", college: "XYZ University")
var allPersons : [Person] = [john, shiva]

Несмотря на то, что «allPersons» - это массив Person, мы поместили в него экземпляры Employee и Student. Это возможно из-за полиморфизма. Объект может одновременно работать как его класс и его родительские классы.

func searchInPhoneBook(_ person: Person) -> String {
    return "\(person.name)"
}
let john = Employee(name: "John", employer: "ABC")
let shiva = Student(name: "Shiva", college: "XYZ University")
searchInPhoneBook(john) . // prints John
searchInPhoneBook(shiva) . // prints shiva

Поскольку john и shiva являются производными от Person, они являются допустимыми входными данными в функцию с типом аргумента Person. Он может наблюдать только элементы Employee / Student, которые определены в базовом классе Person. Это возможно из-за полиморфизма.

Переопределение

Подкласс может предоставлять свою собственную реализацию для свойств или методов, которые он унаследовал, это называется переопределением.

Когда вы переопределяете свойство или метод, вы все равно можете получить доступ к его реализации суперкласса, используя ключевое слово «super» в свойстве или методе суперкласса.

class Animal {
     func makeNoise() {
    // does nothing because an arbitrary vehicle does not make sound 
     }
}
class Dog : Animal {
    override func makeNoise() {
        print("bow bow")
    }
}

Когда Dog издает звук, он переопределяет свой метод суперкласса и предоставляет свою собственную реализацию.

Куда идти дальше: я рассмотрел основы вышеупомянутых тем, вы можете начать.