iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 18
0

繼承

當一個 Class 繼承另一個 Class 時,繼承的 Class 稱為子類 (subclass),被繼承的類稱為他的父類(superclass)。在Swift中,繼承與其他類型不同的基礎分類行為。

在 Swift 中類可以調用和訪問屬於它們父類的方法、屬性和下標腳本,並且可以提供它們自己重寫的方法,屬性和下標腳本來定義或修改它們的行為。Swift 會通過檢查重寫定義都有一個與之匹配的父類定義來確保你的重寫是正確的。

Class 也可以向繼承的屬性添加屬性觀察器,在屬性值改變時得到通知。屬性監視可以添加到任何屬性中,不管它是被定義為存儲屬性還是計算屬性。


定義一個基類

任何不從另一個 Class 繼承的類都是所謂的基類(base class)。

我們下面定義了一個 Transportation 的基類:

class Transportation {
    var speed = 0
    var information: String{
        return "的時速為:\(speed)km/h"
    }
    func distance(hours a:Int) -> Int {
        return speed * a
    }
}

使用初始化語法創建了一個新的 car 實例,寫為他的類型名稱 Transportation 後面跟著一個空括號():

let some  = Transportation()
some.speed = 10
print("這個交通工具\(some.information)")

結果如下:
https://ithelp.ithome.com.tw/upload/images/20180105/20107701WYnB9J9n5B.png

子類 (Subclass)

子類是基於現有 Class 的新類的行為。 子類繼承現有 Class 的特徵,然後可以對其進行優化。你也可以為子類添加新的特性。

我們讓 car 這個 class 去繼承 Transportation,所以我們在 car 後面加上 :Transportation,此時 car 就為 Transportation 的子類,繼承了他的 speed 、information 跟 distance() 方法,同時我們也能為他定義新的屬性:

class car:Transportation {
    var wheel = 4
}

在默認的情況下新建實例,wheel 輪子數量都是為 4 ,但我們可以在創建實例之後去修改其中的值,同時也能更改他繼承的屬性:

let tricycle = car()
tricycle.speed = 1
tricycle.wheel = 3

結果如下:
https://ithelp.ithome.com.tw/upload/images/20180105/20107701rnPB5OrLyn.png

當然子類還是可以繼續被繼承下去的,例如我們這邊再新增一個 ElectricCar 繼承 car 這個 Class:

class ElectricCar:car {
    var enegry = "電力"
}

當然也可以進行上述的操作,他也會繼承到 Transportation 中的特徵,結果如下:
https://ithelp.ithome.com.tw/upload/images/20180105/20107701MYG9TAz5Q3.png

重寫 (Overriding)

一個子類可以提供自己定制的實現方法、類型方法、實例屬性、類型屬性或者下標,否則它們將被父類繼承。這被稱為重寫(overriding)。要覆蓋繼承的特性,可以使用 override 關鍵字在你的定義加上前綴。這樣做說明了你打算重寫一個定義而不是意外提供了一個相同定義。

override關鍵字會執行 Swift 的編譯器檢查你重寫的類的父類(或是父類的父類)是否有與之匹配的聲明來讓你進行重寫。此檢查確保你的重寫的定義是正確的。


訪問父類的方法、屬性和下標腳本

當你為子類提供了一個方法、屬性或者下標腳本時,有時使用父類實現作為重寫的一部分是很有用的。比如說,你可以重新定義現有實現的行為,或者在現有繼承的變數中存儲一個修改過的值。

可以通過使用 super 前綴訪問父類的方法、屬性或下標腳本,這是合適的:

  • 一個命名為 someMethod ( ) 的重寫方法可以通過 super.someMethod( ) 在重寫方法的實現中調用父類版本的 someMethod( ) 方法;
  • 一個命名為 someProperty 的重寫屬性可以通過 super.someProperty 在重寫的 getter 或 setter 實現中訪問父類的 someProperty 屬性;
  • 一個命名為 someIndex 的重寫下標腳本可以使用 super[someIndex] 在重寫的下標腳本實現中訪問父類版本中相同的下標腳本。

重寫方法

我們使用前面交通工具的範例來示範,我們新建一個 broken Class 去繼承交通工具(Transportation) 的 Class,我們將他的 distance() 方法改為無法行駛,並回傳一個整數值:

class broken:Transportation{
    override  func distance(hours a: Int) -> Int {
        print("這台車無法行駛,他的速度為\(speed)")
        return speed * a
    }
}

之後將它放到實例中,執行結果如下:
https://ithelp.ithome.com.tw/upload/images/20180105/20107701ez9egGCa7L.png

重寫屬性

您可以提供一個自定義的 getter(和setter,如果合適的話)來重寫任何繼承的屬性,而不管繼承的屬性是作為存儲屬性還是計算屬性,繼承屬性的存儲屬性或計算屬性不為子類所知的話,它只知道繼承屬性具有特定的名稱和類型。你必須聲明你重寫的屬性名字和類型,以確保編譯器可以檢查你的重寫是否匹配了父類中有相同名字和類型的屬性。

你可以透過在子類屬性重寫中提供 getter 和 setter 來呈現繼承的只讀屬性作為讀寫屬性。但是,不能將繼承的讀寫屬性顯示為只讀屬性。

如果你提供了一個 setter 作為屬性重寫的一部分,你也就必須為重寫提供一個 getter。如果你不想在重寫 getter 時修改繼承屬性的值,那麼你可以簡單通過從 getter 返回 super.someProperty 來傳遞繼承的值, someProperty 就是你重寫的那個屬性的名字。

class Stuck: Transportation {
    override var information: String{
        return "現在阻塞住了!"
    }
}

顯示結果如下:
https://ithelp.ithome.com.tw/upload/images/20180105/20107701a8n8q5FKfR.png


重寫屬性觀察器

你可以使用屬性重寫來將屬性觀察器添加到繼承的屬性,這讓你能夠在繼承屬性的值改變時得到通知,而不管該屬性最初是如何實現的。

你不能將屬性觀察器加到繼承的常數存儲屬性或繼承的只讀計算屬性。 這些屬性的值不能被設置,所以提供一個willSet 或 didSet 實現作為重寫的一部分是不適合的。你也不能同時為同一個屬性提供一個重寫的 setter 和一個重寫屬性觀察器。如果您想觀察對屬性值的更改,並且您已經為該屬性提供了自定義設置器,則可以簡單地觀察自定義設置器中的任何值更改。

我們這邊創建兩個 Class (與上述不同的範例),並且 Train 繼承了 Car:

class Car {
    var distance = 0
    var speed = 25
}

class Train:Car {
    override var speed: Int{
        didSet{
            distance = speed * 20 - speed
        }
    }
}

https://ithelp.ithome.com.tw/upload/images/20180106/201077012P0m3tB53C.png

阻止重寫

你可以通過標記終點來阻止一個方法、屬性或者下標被重寫。通過在方法、屬性或者下標的關鍵字前寫上 final 修飾符,例如: final var ,final func ,final fianl subscript 。任何在子類裡重寫終點方法、屬性或下標的嘗試都會產生編譯錯誤。你在擴展中添加到類的方法、屬性或下標腳本也可以在擴展的定義裡被標記為終點。

你也可以通過在類定義中在 class 關鍵字前面寫 final ,標記一整 個Class為終點。任何想要創建子類的行為都會產生編譯錯誤。


上一篇
Day-17 Swift 語法(13) - 下標 Subscripts
下一篇
Day-19 Swift 語法(15) - 初始化 Initialization
系列文
Swift 菜鳥的30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言