Swift 5.x - 繼承(中文文檔)

引言

繼續學習Swift文檔,從上一章節:下標,咱們學習了Swift下標相關的內容,以下標語法、下標用法、下標選項和類型下標等這些內容。如今,咱們學習Swift的繼承相關的內容。因爲篇幅較長,這裏分篇來記錄,接下來,Fighting!html

熟悉這一章節的朋友能夠直接跳過下一章節:初始化swift

繼承

一個類能夠從另外一個類繼承方法,屬性和其餘特徵。 當一個類從另外一個類繼承時,繼承的類稱爲子類,而其繼承的類稱爲其父類。 繼承是一種基本行爲,可將Swift中的類與其餘類型區分開。bash

Swift中的類能夠調用和訪問屬於其父類的方法,屬性和下標,並能夠提供這些方法,重寫屬性和下標以完善或修改其行爲。 Swift經過檢查覆蓋定義是否具備匹配的父類定義來幫助確保覆蓋是正確的。ide

類還能夠將屬性觀察器添加到繼承的屬性中,以便在屬性值更改時獲得通知。 能夠將屬性觀察器添加到任何屬性,而無論其最初是定義爲存儲屬性仍是計算屬性。post

1 定義基類

任何不從另外一個類繼承的類都稱爲基類。性能

注意
Swift類不能從通用基類繼承。 您沒有指定父類而定義的類將自動成爲基類供您構建。學習

下面的示例定義了一個稱爲Vehicle的基類。 該基類定義了一個稱爲currentSpeed的存儲屬性,默認值爲0.0(推斷屬性類型爲Double)。 currentSpeed屬性的值由一個稱爲description的只讀計算出的String屬性用於建立車輛的描述。優化

Vehicle基類還定義了一個稱爲makeNoise的方法。 此方法實際上不對基礎Vehicle實例執行任何操做,但稍後將由Vehicle的子類自定義:ui

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {
        // do nothing - an arbitrary vehicle doesn't necessarily make a noise } } 複製代碼

使用初始化器語法建立一個Vehicle的新實例,該實例被寫爲類型名稱,後跟空括號:spa

let someVehicle = Vehicle()
複製代碼

建立新的Vehicle實例後,您能夠訪問其description屬性,以打印出人類能夠理解的車輛當前速度的描述:

print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour
複製代碼

Vehicle類定義了任意車輛的共同特徵,但其自己並無太多用途。 爲了使其更有用,您須要對其進行改進以描述更多特定類型的車輛。

2 子類

子類化是在現有類的基礎上創建新類的行爲。 子類繼承現有類的特徵,而後能夠對其進行優化。 您還能夠向子類添加新特徵。

要代表子類具備父類,請在父類名稱以前寫上子類名稱,並用冒號分隔:

class SomeSubclass: SomeSuperclass {
    // subclass definition goes here
}
複製代碼

下面的示例定義了一個名爲Bicycle的子類,並帶有Vehicle的父類:

class Bicycle: Vehicle {
    var hasBasket = false
}
複製代碼

新的Bicycle類自動得到了Vehicle的全部特徵,例如currentSpeed和description屬性以及makeNoise()方法。

除其繼承的特徵外,Bicycle類還定義了一個新的存儲屬性hasBasket,其默認值爲false(爲該屬性推斷爲Bool類型)。

默認狀況下,您建立的任何新Bicycle實例都沒有籃子。 建立特定的Bicycle實例後,能夠將hasBasket屬性設置爲true:

let bicycle = Bicycle()
bicycle.hasBasket = true
複製代碼

您還能夠修改Bicycle實例的繼承的currentSpeed屬性,並查詢該實例的繼承的description屬性:

bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour
複製代碼

子類自己能夠被子類化。 下一個示例爲稱爲「雙人」的兩人座自行車建立Bicycle的子類:

class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}
複製代碼

Tandem繼承了Bicycle的全部屬性和方法,然後者又繼承了Vehicle的全部屬性和方法。 Tandem子類還添加了一個名爲currentNumberOfPassengers的新存儲屬性,默認值爲0。

若是建立Tandem實例,則可使用它的任何新屬性和繼承的屬性,並查詢它從Vehicle繼承的只讀description屬性:

let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print("Tandem: \(tandem.description)")
// Tandem: traveling at 22.0 miles per hour
複製代碼

3 重寫

子類能夠提供其本身的實例方法,類型方法,實例屬性,類型屬性或下標的自定義實現,不然該實例方法將從超類繼承。 這稱爲重寫。

要重寫本來會被繼承的特徵,請在您的重寫定義前添加override關鍵字。 這樣作能夠明確您打算提供替代,而且沒有錯誤地提供匹配的定義。 偶然的重寫可能會致使意外的行爲,而且在編譯代碼時,任何不帶有override關鍵字的替代都會被診斷爲錯誤。

Override關鍵字還會提示Swift編譯器檢查您的重寫類的父類(或其父類之一)是否具備與您爲該替代提供的聲明相匹配的聲明。 此檢查可確保您的重寫定義正確。

3.1 訪問子類的方法、屬性和下標

當爲子類提供方法,屬性或下標替代時,將現有的超類實現用做替代的一部分有時會頗有用。 例如,您能夠優化該現有實現的行爲,或者將修改後的值存儲在現有的繼承變量中。

在適當的狀況下,您可使用super前綴訪問方法,屬性或下標的超類版本:

  • 名稱爲someMethod()的重寫方法能夠經過在重寫方法實現中調用super.someMethod()來調用someMethod()的父類方法。
  • 重寫的名稱爲someProperty的屬性能夠在重寫的getter或setter實現中以super.someProperty的方式訪問someProperty的父類屬性。
  • someIndex的重寫下標能夠從重寫下標實現中訪問與super [someIndex]相同的下標的父類下標。

3.2 重寫方法

您能夠重寫繼承的實例或類型方法,以在子類中提供該方法的定製或替代實現。

如下示例定義了一個名爲Train的Vehicle的新子類,該子類重寫Train從Vehicle繼承的makeNoise()方法:

class Train: Vehicle {
    override func makeNoise() {
        print("Choo Choo")
    }
}
複製代碼

若是建立一個Train的新實例並調用其makeNoise()方法,則能夠看到該方法的Train子類版本稱爲:

let train = Train()
train.makeNoise()
// Prints "Choo Choo"
複製代碼

3.3 重寫屬性

您能夠重寫繼承的實例或類型屬性,覺得該屬性提供本身的自定義getter和setter,或添加屬性觀察器以使重寫的屬性可以在基礎屬性值更改時進行觀察。

重寫屬性的Getters和Setters 您能夠提供一個自定義getter(若是合適的話,可使用setter)來重寫任何繼承的屬性,而無論該繼承的屬性是在源上實現爲存儲屬性仍是計算屬性。 子類不知道繼承屬性的存儲或計算性質,它僅知道繼承屬性具備特定名稱和類型。 您必須始終聲明要重寫的屬性的名稱和類型,以使編譯器可以檢查您的重寫是否與具備相同名稱和類型的父類屬性匹配。

經過在子類屬性重寫中同時提供getter和setter,能夠將繼承的只讀屬性呈現爲讀寫屬性。 可是,您不能將繼承的讀寫屬性表示爲只讀屬性。

注意
若是在屬性替代中提供了一個setter,則還必須爲該替代提供一個getter。 若是您不想在重寫的getter中修改繼承的屬性的值,則能夠經過從getter返回super.someProperty來傳遞繼承的值,其中someProperty是您要重寫的屬性的名稱。

如下示例定義了一個名爲Car的新類,它是Vehicle的子類。 Car類引入了一個稱爲gear的新存儲屬性,其默認整數值爲1。Car類還覆蓋了它從Vehicle繼承的description屬性,以提供包括當前gear的自定義描述:

class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}
複製代碼

對description屬性的重寫是經過調用super.description開始的,super.description返回Vehicle類的description屬性。 而後,汽車類的描述版本會在此描述的末尾添加一些額外的文字,以提供有關當前裝備的信息。

若是建立Car類的實例並設置其gear和currentSpeed屬性,則能夠看到其description屬性返回在Car類中定義的定製描述:

let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// Car: traveling at 25.0 miles per hour in gear 3
複製代碼

重寫屬性監聽 您可使用屬性重寫將屬性觀察器添加到繼承的屬性。 這使您能夠在繼承屬性的值更改時獲得通知,而不管該屬性最初是如何實現的。 有關屬性觀察器的更多信息,請參見Property Observers

注意
您不能將屬性觀察器添加到繼承的常量存儲屬性或繼承的只讀計算屬性。 這些屬性的值沒法設置,所以不建議將willSet或didSet實現做爲覆蓋的一部分提供。

還要注意,您不能爲同一屬性同時提供覆蓋設置器和覆蓋屬性觀察器。 若是您想觀察屬性值的變化,而且已經在爲該屬性提供自定義設置器,則能夠簡單地觀察自定義設置器中的任何值更改。

下面的示例定義一個名爲AutomaticCar的新類,它是Car的子類。 AutomaticCar類表明具備自動變速箱的汽車,該變速箱會根據當前速度自動選擇要使用的檔位:

class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            gear = Int(currentSpeed / 10.0) + 1
        }
    }
}
複製代碼

每當您設置AutomaticCar實例的currentSpeed屬性時,該屬性的didSet觀察器都會將該實例的gear屬性設置爲新速度的適當齒輪。 具體來講,屬性觀察者選擇的齒輪是新的currentSpeed值除以10,四捨五入到最接近的整數加1。35.0的速度產生4的齒輪:

let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4
複製代碼

4 防止重寫

您能夠經過將方法,屬性或下標標記爲final來防止其被重寫。 爲此,能夠在方法,屬性或下標的Introductionr關鍵字(例如final var,final func,final class func和final下標)以前編寫final修飾符。

嘗試重寫子類中的最終方法,屬性或下標的任未嘗試都將報告爲編譯時錯誤。 您在擴展程序的類中添加的方法,屬性或下標也能夠在擴展程序的定義中標記爲final。

您能夠經過在類定義中的class關鍵字以前編寫final修飾符,將整個類標記爲(final class)。 任未嘗試將最終類做爲子類的嘗試都將報告爲編譯時錯誤。

總結

這一章節主要講的是:

  • 繼承的做用:能夠繼承父類定義的屬性、方法和下標,以擴展自定義的功能。
  • 沒有從父類繼承的類都是基類,在基類裏面定義一些基本的屬性個方法,以提供子類來擴展。
  • 使用override關鍵詞修飾父類的屬性或方法來重寫父類裏面實現的功能。能夠重寫屬性的Getters和Setters、屬性監聽。
  • 使用final關鍵詞修飾能夠防止重寫。

好了,有收穫的朋友麻煩給個鼓勵哦,謝謝啦~

上一章節:下標

下一章節:初始化

參考文檔: Swift - Inheritance

相關文章
相關標籤/搜索