【Swift學習】Swift編程之旅---繼承(十七)

  在 Swift 中,繼承是區分「類」與其它類型的一個基本特徵。swift不支持多重繼承。類能夠調用和訪問超類的方法,屬性和subscripts下標,而且能夠重寫(override)這些方法,屬性和附屬腳原本優化或修改它們的行爲。Swift 會檢查你的重寫定義在超類中是否有匹配的定義,以此確保你的重寫行爲是正確的。swift

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

  

  基類的定義ide

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

注意:Swift 中的類並非從一個通用的基類繼承而來。若是你不爲你定義的類指定一個超類的話,這個類就自動成爲基類。
下面的例子定義了一個叫Vehicle的基類。這個基類聲明瞭兩個對全部車輛都通用的屬性(numberOfWheels和maxPassengers)。這些屬性在description方法中使用,這個方法返回一個String類型的,對車輛特徵的描述:
class Vehicle { var numberOfWheels: Int var maxPassengers: Int func description() -> String { return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers" } init() { numberOfWheels = 0 maxPassengers = 1 } } 
 
   子類化
 
   子類化是子類繼承超類的特性,而且能夠優化或改變它。你還能夠爲子類添加新的特性。
爲了指明某個類的超類,將超類名寫在子類名的後面,用冒號分隔:
class SomeClass: SomeSuperclass { // 類的定義 
} 

 

下一個例子,定義一個更具體的車輛類叫Bicycle。這個新類是在 Vehicle類的基礎上建立起來。所以你須要將Vehicle類放在 Bicycle類後面,用冒號分隔。
class Bicycle: Vehicle { init() { super.init() numberOfWheels = 2 } }
Bicycle是Vehicle的子類,Vehicle是Bicycle的超類。新的Bicycle類自動得到Vehicle類的特性,好比 maxPassengers和numberOfWheels屬性。你能夠在子類中定製這些特性,或添加新的特性來更好地描述Bicycle類。
 
Bicycle類定義了一個構造器來設置它定製的特性(自行車只有2個輪子)。Bicycle的構造器調用了它父類Vehicle的構造器 super.init(),以此確保在Bicycle類試圖修改那些繼承來的屬性前Vehicle類已經初始化過它們了。
 
注意:不像 Objective-C,在 Swift 中,初始化器默認是不繼承的。
 
Vehicle類中maxPassengers的默認值對自行車來講已是正確的,所以在Bicycle的構造器中並無改變它。而numberOfWheels原來的值對自行車來講是不正確的,所以在初始化器中將它更改成 2。
 
Bicycle不只能夠繼承Vehicle的屬性,還能夠繼承它的方法。若是你建立了一個Bicycle類的實例,你就能夠調用它繼承來的description方法,而且能夠看到,它輸出的屬性值已經發生了變化:
 
let bicycle = Bicycle() println("Bicycle: \(bicycle.description())") // Bicycle: 2 wheels; up to 1 passengers 

 子類還能夠繼續被其它類繼承:優化

class Tandem: Bicycle { init() { super.init() maxPassengers = 2 } } 

意:子類只容許修改從超類繼承來的變量屬性,而不能修改繼承來的常量屬性。spa

 

  重寫(Overriding)code

  子類能夠爲繼承來的實例方法(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]來訪問超類版本中的相同下標。
 
1.重寫方法
class Car: Vehicle { var speed: Double = 0.0 init() { super.init() maxPassengers = 5 numberOfWheels = 4 } override func description() -> String { return super.description() + "; " 
            + "traveling at \(speed) mph" } } 

 

Car聲明瞭一個新的存儲型屬性speed,它是Double類型的,默認值是0.0,表示「時速是0英里」。Car有本身的初始化器,它將乘客的最大數量設爲5,輪子數量設爲4。
 
Car重寫了繼承來的description方法,它的聲明與Vehicle中的description方法一致,聲明前面加上了override關鍵字。
 
Car中的description方法並不是徹底自定義,而是經過super.description使用了超類Vehicle中的description方法,而後再追加一些額外的信息,好比汽車的當前速度。
 
若是你建立一個Car的新實例,並打印description方法的輸出,你就會發現描述信息已經發生了改變
let car = Car() println("Car: \(car.description())") // Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph 

 

2. 重寫屬性
你能夠重寫繼承來的實例屬性或類屬性,提供本身定製的getter和setter,或添加屬性觀察器使重寫的屬性觀察屬性值何時發生改變。
 
3.重寫屬性的Getters和Setters
你能夠提供定製的 getter(或 setter)來重寫任意繼承來的屬性,不管繼承來的屬性是存儲型的仍是計算型的屬性。子類並不知道繼承來的屬性是存儲型的仍是計算型的,它只知道繼承來的屬性會有一個名字和類型。你在重寫一個屬性時,必需將它的名字和類型都寫出來。這樣才能使編譯器去檢查你重寫的屬性是與超類中同名同類型的屬性相匹配的。
 
你能夠將一個繼承來的只讀屬性重寫爲一個讀寫屬性,只須要你在重寫版本的屬性裏提供 getter 和 setter 便可。可是,你不能夠將一個繼承來的讀寫屬性重寫爲一個只讀屬性。
 
注意:若是你在重寫屬性中提供了 setter,那麼你也必定要提供 getter。若是你不想在重寫版本中的 getter 裏修改繼承來的屬性值,你能夠直接返回super.someProperty來返回繼承來的值。正以下面的SpeedLimitedCar的例子所示。
 
如下的例子定義了一個新類,叫SpeedLimitedCar,它是Car的子類。類SpeedLimitedCar表示安裝了限速裝置的車,它的最高速度只能達到40mph。你能夠經過重寫繼承來的speed屬性來實現這個速度限制
class SpeedLimitedCar: Car { override var speed: Double { get { return super.speed } set { super.speed = min(newValue, 40.0) } } } 

 

當你設置一個SpeedLimitedCar實例的speed屬性時,屬性setter的實現會去檢查新值與限制值40mph的大小,它會將超類的speed設置爲newValue和40.0中較小的那個。這兩個值哪一個較小由min函數決定,它是Swift標準庫中的一個全局函數。min函數接收兩個或更多的數,返回其中最小的那個。
 
若是你嘗試將SpeedLimitedCar實例的speed屬性設置爲一個大於40mph的數,而後打印description函數的輸出,你會發現速度被限制在40mph:
let limitedCar = SpeedLimitedCar() limitedCar.speed = 60.0 println("SpeedLimitedCar: \(limitedCar.description())") // SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph 
4.重寫屬性觀察器(Property Observer)
你能夠在屬性重寫中爲一個繼承來的屬性添加屬性觀察器。這樣一來,當繼承來的屬性值發生改變時,你就會被通知到,不管那個屬性本來是如何實現的。關於屬性觀察器的更多內容,請看屬性觀察器。
 
注意:你不能夠爲繼承來的常量存儲型屬性或繼承來的只讀計算型屬性添加屬性觀察器。這些屬性的值是不能夠被設置的,因此,爲它們提供willSet或didSet實現是不恰當。此外還要注意,你不能夠同時提供重寫的 setter 和重寫的屬性觀察器。若是你想觀察屬性值的變化,而且你已經爲那個屬性提供了定製的 setter,那麼你在 setter 中就能夠觀察到任何值變化了。
 
下面的例子定義了一個新類叫AutomaticCar,它是Car的子類。AutomaticCar表示自動擋汽車,它能夠根據當前的速度自動選擇合適的擋位。AutomaticCar也提供了定製的description方法,能夠輸出當前擋位。
class AutomaticCar: Car { var gear = 1 
    override var speed: Double { didSet { gear = Int(speed / 10.0) + 1 } } override func description() -> String { return super.description() + " in gear \(gear)" } } 

當你設置AutomaticCar的speed屬性,屬性的didSet觀察器就會自動地設置gear屬性,爲新的速度選擇一個合適的擋位。具體來講就是,屬性觀察器將新的速度值除以10,而後向下取得最接近的整數值,最後加1來獲得檔位gear的值。例如,速度爲10.0時,擋位爲1;速度爲35.0時,擋位爲4:server

let automatic = AutomaticCar() automatic.speed = 35.0 println("AutomaticCar: \(automatic.description())") // AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4 

 

  

  防止重寫blog

你能夠經過把方法,屬性或下標標記爲final來防止它們被重寫,只須要在聲明關鍵字前加上final特性便可。(例如:final var, final func, final class func, 以及 final subscript)
 
若是你重寫了final方法,屬性或下標,在編譯時會報錯。在擴展中,你添加到類裏的方法,屬性或下標也能夠在擴展的定義裏標記爲 final。
 
你能夠經過在關鍵字class前添加@final特性(final class)來將整個類標記爲 final 的,這樣的類是不可被繼承的,不然會報編譯錯誤。
相關文章
相關標籤/搜索