Swift 繼承


繼承我們可以理解為一個類別取得了另外一個類別的方法和屬性。

當一個類別繼承其它類別時,繼承類別叫子類,被繼承類別叫做超類別(或父類)

在Swift 中,類別可以呼叫和存取超類別的方法,屬性和下標腳本,並且可以重寫它們。

我們也可以為類別中繼承來的屬性新增屬性觀察器。


基底類別

沒有繼承其它類別的類,稱為基底類別(Base Class)。

以下實例中我們定義了基類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

print(stname)
print(mark1)
print(mark2)
print(mark3)

以上程式執行輸出結果為:

swift
98
89
76
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

重寫(Overriding)

子類別可以透過繼承的實例方法,類別方法,實例屬性,或下標腳本來實作自己的自訂功能,我們把這種行為叫做重寫(overriding)。

我們可以使用 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

重寫屬性

你可以提供客製化的getter(或setter)來重寫任意繼承來的屬性,無論繼承來的屬性是儲存型的還是計算型的屬性。

子類別並不知道繼承來的屬性是儲存型的還是運算型的,它只知道繼承來的屬性會有一個名字和型別。所以你在重寫一個屬性時,必需將它的名字和類型都寫出來。

注意點:

  • 如果你在重寫屬性中提供了 setter,那麼你也一定要提供 getter。

  • 如果你不想在重寫版本中的getter 裡修改繼承來的屬性值,你可以直接透過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方法,屬性或下標腳本,在編譯時會報錯。

你可以透過在關鍵字class前面加入final特性(final class)來標記整個類別為 final 的,這樣的類別是不可被繼承的,否則會報編譯錯誤。

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 {
      ^
重寫訪問方法,屬性,下標腳本