位置:首頁 > 高級語言 > Swift教學 > Swift重寫

Swift重寫

重寫(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的一個新的子類,叫Car,它重寫了從Vehicle類繼承來的description方法:

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

重寫屬性

你可以重寫繼承來的實例屬性或類屬性,提供自己定製的getter和setter,或添加屬性觀察器使重寫的屬性觀察屬性值什麼時候發生改變。

重寫屬性的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設置為newValue40.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

重寫屬性觀察器(Property Observer)

你可以在屬性重寫中為一個繼承來的屬性添加屬性觀察器。這樣一來,當繼承來的屬性值發生改變時,你就會被通知到,無論那個屬性原本是如何實現的。關於屬性觀察器的更多內容,請看屬性觀察器


注意:
你不可以為繼承來的常量存儲型屬性或繼承來的隻讀計算型屬性添加屬性觀察器。這些屬性的值是不可以被設置的,所以,為它們提供willSetdidSet實現是不恰當。此外還要注意,你不可以同時提供重寫的 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)"
    }
}

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

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