Swift-2.13繼承

本頁包含內容:html

一個類能夠繼承(inherit)另外一個類的方法(methods),屬性(properties)和其它特性。當一個類繼承其它類時,繼承類叫子類(subclass),被繼承類叫超類(或父類,superclass)。在 Swift 中,繼承是區分「類」與其它類型的一個基本特徵。swift

在 Swift 中,類能夠調用和訪問超類的方法,屬性和下標腳本(subscripts),而且能夠重寫(override)這些方法,屬性和下標腳原本優化或修改它們的行爲。Swift 會檢查你的重寫定義在超類中是否有匹配的定義,以此確保你的重寫行爲是正確的。ide

能夠爲類中繼承來的屬性添加屬性觀察器(property observers),這樣一來,當屬性值改變時,類就會被通知到。能夠爲任何屬性添加屬性觀察器,不管它本來被定義爲存儲型屬性(stored property)仍是計算型屬性(computed property)。優化

定義一個基類(Base class)

不繼承於其它類的類,稱之爲基類(base calss)ui

注意
Swift 中的類並非從一個通用的基類繼承而來。若是你不爲你定義的類指定一個超類的話,這個類就自動成爲基類。spa

下面的例子定義了一個叫Vehicle的基類。這個基類聲明瞭一個名爲currentSpeed,默認值是0.0的存儲屬性(屬性類型推斷爲Double)。currentSpeed屬性的值被一個String類型的只讀計算型屬性description使用,用來建立車輛的描述。code

Vehicle基類也定義了一個名爲makeNoise的方法。這個方法實際上不爲Vehicle實例作任何事,但以後將會被Vehicle的子類定製:server

class Vehicle { var currentSpeed = 0.0 var description: String { return "traveling at \(currentSpeed) miles per hour" } func makeNoise() { // 什麼也不作-由於車輛不必定會有噪音 } } 

您能夠用初始化語法建立一個Vehicle的新實例,即類名後面跟一個空括號:htm

let someVehicle = Vehicle() 

如今已經建立了一個Vehicle的新實例,你能夠訪問它的description屬性來打印車輛的當前速度:繼承

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

Vehicle類定義了一個通用特性的車輛類,實際上沒什麼用處。爲了讓它變得更加有用,須要完善它從而可以描述一個更加具體類型的車輛。

子類生成(Subclassing)

子類生成(Subclassing)指的是在一個已有類的基礎上建立一個新的類。子類繼承超類的特性,而且能夠進一步完善。你還能夠爲子類添加新的特性。

爲了指明某個類的超類,將超類名寫在子類名的後面,用冒號分隔:

class SomeClass: SomeSuperclass { // 這裏是子類的定義 } 

下一個例子,定義一個叫Bicycle的子類,繼承成父類Vehicle

class Bicycle: Vehicle { var hasBasket = false } 

新的Bicycle類自動得到Vehicle類的全部特性,好比currentSpeeddescription屬性,還有它的makeNoise()方法。

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

默認狀況下,你建立任何新的Bicycle實例將不會有一個籃子(即hasBasket屬性默認爲false),建立該實例以後,你能夠爲特定的Bicycle實例設置hasBasket屬性爲ture

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建立了一個名爲Tandem(雙人自行車)的子類:

class Tandem: Bicycle { var currentNumberOfPassengers = 0 } 

TandemBicycle繼承了全部的屬性與方法,這又使它同時繼承了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 

重寫(Overriding)

子類能夠爲繼承來的實例方法(instance method),類方法(class method),實例屬性(instance property),或下標腳本(subscript)提供本身定製的實現(implementation)。咱們把這種行爲叫重寫(overriding)

若是要重寫某個特性,你須要在重寫定義的前面加上override關鍵字。這麼作,你就代表了你是想提供一個重寫版本,而非錯誤地提供了一個相同的定義。意外的重寫行爲可能會致使不可預知的錯誤,任何缺乏override關鍵字的重寫都會在編譯時被診斷爲錯誤。

override關鍵字會提醒 Swift 編譯器去檢查該類的超類(或其中一個父類)是否有匹配重寫版本的聲明。這個檢查能夠確保你的重寫定義是正確的。

訪問超類的方法,屬性及下標腳本

當你在子類中重寫超類的方法,屬性或下標腳本時,有時在你的重寫版本中使用已經存在的超類實現會大有裨益。好比,你能夠完善已有實現的行爲,或在一個繼承來的變量中存儲一個修改過的值。

在合適的地方,你能夠經過使用super前綴來訪問超類版本的方法,屬性或下標腳本:

  • 在方法someMethod()的重寫實現中,能夠經過super.someMethod()來調用超類版本的someMethod()方法。
  • 在屬性someProperty的 getter 或 setter 的重寫實現中,能夠經過super.someProperty來訪問超類版本的someProperty屬性。
  • 在下標腳本的重寫實現中,能夠經過super[someIndex]來訪問超類版本中的相同下標腳本。

重寫方法

在子類中,你能夠重寫繼承來的實例方法或類方法,提供一個定製或替代的方法實現。

下面的例子定義了Vehicle的一個新的子類,叫Train,它重寫了從Vehicle類繼承來的makeNoise()方法:

class Train: Vehicle { override func makeNoise() { print("Choo Choo") } } 

若是你建立一個Train的新實例,並調用了它的makeNoise()方法,你就會發現Train版本的方法被調用:

let train = Train() train.makeNoise() // 打印 "Choo Choo" 

重寫屬性

你能夠重寫繼承來的實例屬性或類型屬性,提供本身定製的 getter 和 setter,或添加屬性觀察器使重寫的屬性能夠觀察屬性值何時發生改變。

重寫屬性的 Getters 和 Setters

你能夠提供定製的 getter(或 setter)來重寫任意繼承來的屬性,不管繼承來的屬性是存儲型的仍是計算型的屬性。子類並不知道繼承來的屬性是存儲型的仍是計算型的,它只知道繼承來的屬性會有一個名字和類型。你在重寫一個屬性時,必需將它的名字和類型都寫出來。這樣才能使編譯器去檢查你重寫的屬性是與超類中同名同類型的屬性相匹配的。

你能夠將一個繼承來的只讀屬性重寫爲一個讀寫屬性,只須要在重寫版本的屬性裏提供 getter 和 setter 便可。可是,你不能夠將一個繼承來的讀寫屬性重寫爲一個只讀屬性。

注意
若是你在重寫屬性中提供了 setter,那麼你也必定要提供 getter。若是你不想在重寫版本中的 getter 裏修改繼承來的屬性值,你能夠直接經過super.someProperty來返回繼承來的值,其中someProperty是你要重寫的屬性的名字。

如下的例子定義了一個新類,叫Car,它是Vehicle的子類。這個類引入了一個新的存儲型屬性叫作gear,默認值爲整數1Car類重寫了繼承自Vehicledescription屬性,提供包含當前檔位的自定義描述:

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

重寫的description屬性首先要調用super.description返回Vehicle類的description屬性。以後,Car類版本的description在末尾增長了一些額外的文原本提供關於當前檔位的信息。

若是你建立了Car的實例而且設置了它的gearcurrentSpeed屬性,你能夠看到它的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 Observer)

你能夠經過重寫屬性爲一個繼承來的屬性添加屬性觀察器。這樣一來,當繼承來的屬性值發生改變時,你就會被通知到,不管那個屬性本來是如何實現的。關於屬性觀察器的更多內容,請看屬性觀察器

注意
你不能夠爲繼承來的常量存儲型屬性或繼承來的只讀計算型屬性添加屬性觀察器。這些屬性的值是不能夠被設置的,因此,爲它們提供willSetdidSet實現是不恰當。
此外還要注意,你不能夠同時提供重寫的 setter 和重寫的屬性觀察器。若是你想觀察屬性值的變化,而且你已經爲那個屬性提供了定製的 setter,那麼你在 setter 中就能夠觀察到任何值變化了。

下面的例子定義了一個新類叫AutomaticCar,它是Car的子類。AutomaticCar表示自動擋汽車,它能夠根據當前的速度自動選擇合適的擋位:

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

當你設置AutomaticCarcurrentSpeed屬性,屬性的didSet觀察器就會自動地設置gear屬性,爲新的速度選擇一個合適的擋位。具體來講就是,屬性觀察器將新的速度值除以10,而後向下取得最接近的整數值,最後加1來獲得檔位gear的值。例如,速度爲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 

防止重寫

你能夠經過把方法,屬性或下標腳本標記爲final來防止它們被重寫,只須要在聲明關鍵字前加上final修飾符便可(例如:final varfinal funcfinal class func,以及final subscript)。

若是你重寫了final方法,屬性或下標腳本,在編譯時會報錯。在類擴展中的方法,屬性或下標腳本也能夠在擴展的定義裏標記爲 final 的。

你能夠經過在關鍵字class前添加final修飾符(final class)來將整個類標記爲 final 的。這樣的類是不可被繼承的,試圖繼承這樣的類會致使編譯報錯。

相關文章
相關標籤/搜索