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

Наследование можно понимать как приобретение одним классом методов и свойств другого класса.

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

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

Мы также можем добавлять наблюдателей свойств к свойствам, унаследованным классом.


Базовый класс

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

В следующем примере мы определяем базовый класс StudDetails, который описывает студента (stname) и его оценки по различным предметам (mark1, mark2, mark3):

class StudDetails {
    var stname: String!
    var mark1: Int!
    var mark2: Int!
    var mark3: Int!
    init(stname: String, mark1: Int, mark2: Int, mark3: Int) {
        self.stname = stname
        self.mark1 = mark1
        self.mark2 = mark2
        self.mark3 = mark3
    }
}
let stname = "swift"
let mark1 = 98
let mark2 = 89
let mark3 = 76

let sds = StudDetails(stname:stname, mark1:mark1, mark2:mark2, mark3:mark3);

print(sds.stname)
print(sds.mark1)
print(sds.mark2)
print(sds.mark3)

Вывод выполнения вышеуказанной программы:

swift
98
89
76

Подкласс

Подкласс означает создание нового класса на основе существующего класса.

Чтобы указать суперкласс класса, напишите имя суперкласса после имени подкласса, разделив их двоеточием (:). Формат синтаксиса следующий:

class SomeClass: SomeSuperclass {
    // 类的定义
}

Примеры

В следующем примере мы определяем суперкласс StudDetails, а затем используем подкласс Tom для его наследования:

class StudDetails
{
    var mark1: Int;
    var mark2: Int;
    
    init(stm1:Int, results stm2:Int)
    {
        mark1 = stm1;
        mark2 = stm2;
    }
    
    func show()
    {
        print("Mark1:\(self.mark1), Mark2:\(self.mark2)")
    }
}

class Tom : StudDetails
{
    init()
    {
        super.init(stm1: 93, results: 89)
    }
}

let tom = Tom()
tom.show()

Вывод выполнения вышеуказанной программы:

Mark1:93, Mark2:89

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

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

Мы можем использовать ключевое слово override для реализации переопределения.

Доступ к методам, свойствам и сабскриптам суперкласса

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

Переопределение Доступ к методам, свойствам и сабскриптам
Методы super.somemethod()
Свойства super.someProperty()
Индексы super[someIndex]

Переопределение методов и свойств

Переопределение методов

В нашем подклассе мы можем использовать ключевое слово override для переопределения методов суперкласса.

В следующем примере мы переопределяем метод show():

class SuperClass {
    func show() {
        print("这是超类 SuperClass")
    }
}

class SubClass: SuperClass  {
    override func show() {
        print("这是子类 SubClass")
    }
}

let superClass = SuperClass()
superClass.show()

let subClass = SubClass()
subClass.show()

Вывод выполнения вышеуказанной программы:

这是超类 SuperClass
这是子类 SubClass

Переопределение свойств

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

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

Примечания:

  • Если вы предоставляете сеттер в переопределённом свойстве, вы также должны предоставить геттер.

  • Если вы не хотите изменять значение унаследованного свойства в геттере переопределяющей версии, вы можете напрямую вернуть унаследованное значение через super.someProperty, где someProperty — имя переопределяемого свойства.

В следующем примере мы определяем суперкласс Circle и подкласс Rectangle. В классе Rectangle мы переопределяем свойство area:

class Circle {
    var radius = 12.5
    var area: String {
        return "矩形半径 \(radius) "
    }
}

// 继承超类 Circle
class Rectangle: Circle {
    var print = 7
    override var area: String {
        return super.area + " ,但现在被重写为 \(print)"
    }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

Вывод выполнения вышеуказанной программы:

Radius 矩形半径 25.0  ,但现在被重写为 3

Переопределение наблюдателей свойств

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

Примечание:Вы не можете добавлять наблюдателей свойств к унаследованным константным хранимым свойствам или унаследованным вычисляемым свойствам только для чтения.

class Circle {
    var radius = 12.5
    var area: String {
        return "矩形半径为 \(radius) "
    }
}

class Rectangle: Circle {
    var print = 7
    override var area: String {
        return super.area + " ,但现在被重写为 \(print)"
    }
}


let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("半径: \(rect.area)")

class Square: Rectangle {
    override var radius: Double {
        didSet {
            print = Int(radius/5.0)+1
        }
    }
}


let sq = Square()
sq.radius = 100.0
print("半径: \(sq.area)")
半径: 矩形半径为 25.0  ,但现在被重写为 3
半径: 矩形半径为 100.0  ,但现在被重写为 21

Предотвращение переопределений

Мы можем использовать ключевое слово final, чтобы предотвратить их переопределение.

Если вы переопределите метод, свойство или сабскрипт, помеченные как final, возникнет ошибка на этапе компиляции.

Вы можете пометить весь класс как final, добавив модификатор final (final class) перед ключевым словом class. Такой класс невозможно наследовать; в противном случае возникнет ошибка компиляции.

final class Circle {
    final var radius = 12.5
    var area: String {
        return "矩形半径为 \(radius) "
    }
}
class Rectangle: Circle {
    var print = 7
    override var area: String {
        return super.area + " ,但现在被重写为 \(print)"
    }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("半径: \(rect.area)")

class Square: Rectangle {
    override var radius: Double {
        didSet {
            print = Int(radius/5.0)+1
        }
    }
}

let sq = Square()
sq.radius = 100.0
print("半径: \(sq.area)")

Поскольку в приведённом выше примере используется ключевое слово final и переопределение не допускается, выполнение приведёт к ошибке:

error: var overrides a 'final' var
    override var area: String {
                 ^
note: overridden declaration is here
    var area: String {
        ^
error: var overrides a 'final' var
    override var radius: Double {
                 ^
note: overridden declaration is here
    final var radius = 12.5
              ^
error: inheritance from a final class 'Circle'
class Rectangle: Circle {
      ^
Другие расширения