天天看點

Swift程式設計十四(繼承)繼承

案例代碼下載下傳

繼承

類可以從另一個類繼承方法,屬性和其他特性。當一個類繼承自另一個類時,繼承類稱為子類,它繼承的類稱為其超類。繼承是一種基本行為,它将類與Swift中的其他類型區分開來。

Swift中的類可以調用和通路屬于其超類的方法,屬性和下标,并可以提供這些方法,屬性和下标的自己的重寫版本,以優化或修改它們的行為。Swift通過檢查覆寫定義是否具有比對的超類定義來幫助確定覆寫是正确的。

類還可以将屬性觀察者添加到繼承的屬性,以便在屬性值更改時得到通知。屬性觀察者可以添加到任何屬性,無論它最初是被定義為存儲屬性還是計算屬性。

定義基類

任何不從其他類繼承的類都稱為基類。

注意: Swift類不從通用基類繼承。在不指定超類的情況下定義的類會自動成為建構的基類。

下面的示例定義了一個名為Vehicle的基類。此基類定義一個名為currentSpeed的存儲屬性,其預設值為0.0(推斷屬性類型為Double)。currentSpeed屬性的值由一個隻讀的String計算屬性使用,該屬性被description調用以建立車輛的描述。

所述Vehicle基類還定義了一個稱為makeNoise的方法。此方法實際上并不對基本Vehicle執行個體執行任何操作,将由Vehicle以後的子類自定義:

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {
        // do nothing
    }
}
           

Vehicle使用初始化程式文法建立一個新執行個體,該文法寫為類型名稱,後跟空括号:

let someVehicle = Vehicle()
           

建立新Vehicle執行個體後,可以通路其description屬性以列印車輛目前速度的可讀描述:

print(someVehicle.description)
           

在Vehicle類定義的共同特點為任意車輛,但本身沒有太大用處。為了使其更有用,需要對其進行優化以描述更具體的車輛類型。

子類

子類化是在現有類上建立新類的行為。子類繼承現有類的特征,然後可以對其進行細化。還可以向子類添加新特征。

要訓示子類具有超類,請在超類名稱之前寫入子類名稱,用冒号分隔:

class SomeSubclass: SomeSuperclass {
    // 子類在這裡定義
}
           

以下示例定義了一個名為的子類Bicycle,其超類為Vehicle:

class Bicycle: Vehicle {
    var hasBasket = false
}
           

新的Bicycle類自動獲得Vehicle所有的特性,例如它的currentSpeed和description屬性及其makeNoise()方法。

除了它繼承的特性之外,Bicycle該類還定義了一個新的存儲屬性,hasBasket其預設值為false(推斷屬性的類型為Bool)。

預設情況下,Bicycle建立的任何新執行個體都不會有籃子。可以在建立該執行個體後将hasBasket屬性設定true為特定Bicycle執行個體:

let bicycle = Bicycle()
bicycle.hasBasket = true
           

還可以修改Bicycle執行個體繼承的一個屬性currentSpeed,查詢執行個體的繼承description屬性:

bicycle.currentSpeed = 15.0
print(bicycle.description)
           

子類本身可以建立子類。下一個示例為Bicycle車建立一個雙座自行子類,稱為“tandem”:

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.description)
           

重寫

子類可以提供自己的執行個體方法,類型方法,執行個體屬性,類型屬性或下标的自定義實作,否則它将從超類繼承。這被稱為重寫。

要覆寫否則将繼承的特性,使用override關鍵字為覆寫定義添加字首。這樣做可以澄清打算提供覆寫并且不會提供錯誤的比對定義。意外覆寫可能會導緻意外行為,并且在編譯代碼時,沒有override關鍵字的任何覆寫都會被診斷為錯誤。

override關鍵字還會提示Swift編譯器檢查重寫類的超類(或其父類之一)是否具有與重寫提供的聲明比對的聲明。此檢查可確定您的重寫定義正确無誤。

通路超類方法,屬性和下标

當為子類提供方法,屬性或下标覆寫時,将現有超類實作用作覆寫的一部分有時很有用。例如,可以優化現有實作的行為,或将修改後的值存儲在現有的繼承變量中。

如果這是合适的,可以使用super字首通路方法,屬性或下标的超類版本:

  • 重寫方法someMethod()可以通過super.someMethod()在重寫方法實作中調用超類版本someMethod()。
  • 重寫載的someProperty屬性可以通過super.someProperty在重寫的getter或setter實作中通路的超類版本的someProperty屬性。
  • 重寫的someIndex下标可以通過super[someIndex]從重寫的下标實作中通路同一下标的超類版本。

重寫方法

可以覆寫繼承的執行個體或類型方法,以在子類中提供方法的定制或替代實作。

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

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

如果建立一個Train新執行個體并調用其makeNoise()方法,則可以看到該方法的Train子類版本被調用:

let train = Train()
train.makeNoise()
           

重寫屬性

可以覆寫繼承的執行個體或類型屬性,以便為該屬性提供自己的自定義getter和setter,或添加屬性觀察器以使覆寫屬性能夠在基礎屬性值更改時進行觀察。

覆寫屬性getter和setter

可以提供自定義getter(和setter,如果适用)以覆寫任何繼承的屬性,無論繼承的屬性是在源上實作為存儲屬性還是計算屬性。子類不知道繼承屬性的存儲或計算性質 - 它隻知道繼承的屬性具有特定的名稱和類型。必須始終聲明要覆寫的屬性的名稱和類型,以使編譯器能夠檢查的覆寫是否與具有相同名稱和類型的超類屬性比對。

通過在子類屬性覆寫提供getter和setter,可以将繼承的隻讀屬性作為讀寫屬性提供。但是,不能将繼承的讀寫屬性顯示為隻讀屬性。

注意: 如果将setter作為屬性覆寫的一部分提供,則還必須為該覆寫提供getter。如果不想在覆寫的getter中修改繼承屬性的值,則可以通過super.someProperty從getter 傳回來簡單地傳遞繼承的值,其中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開始,它傳回Vehicle類的description屬性。然後,Car該類的版本description在本描述的末尾添加了一些額外的文本,以提供有關目前檔位的資訊。

如果你建立Car類的執行個體,并設定它gear和currentSpeed屬性,你可以看到它的description屬性傳回中Car類定義的定制描述:

let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print(car.description)
           

覆寫屬性觀察器

可以使用重寫屬性将屬性觀察器添加到繼承的屬性。這使可以在繼承屬性的值更改時收到通知,無論該屬性最初如何實作。有關屬性觀察者的更多資訊,請參閱Property Observers。

注意: 不能将屬性觀察器添加到繼承的常量存儲屬性或繼承的隻讀計算屬性。無法設定這些屬性的值,是以不适合提供willSet或didSet實作作為覆寫的一部分。 另請注意,不能同時為同一屬性提供重寫setter和屬性觀察器。如果要觀察屬性值的更改,并且已經為該屬性提供了自定義setter,則隻需觀察自定義setter中的任何值更改即可。

下面的示例定義了一個名為AutomaticCar的新類,它是一個Car子類。所述AutomaticCar類表示用自動變速器,自動選擇适當的gear适用于目前速度的一輛車:

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

當你設定一個AutomaticCar執行個體的currentSpeed屬性,屬性的didSet觀察者設定執行個體的gear屬性根據新速度的一個合适選擇。具體來說,屬性觀察者選擇一個新currentSpeed值除以10,向下舍入到最接近的整數,加1。35.0的速度産生gear為4:

let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print(automatic.description)
           

防止覆寫

可以通過将方法,屬性或下标标記為final來阻止它被覆寫。通過在方法,屬性,或下标的申明關鍵字之前寫final修飾符做到這一點(如final var,final func,final class func,和final subscript)。

任何覆寫子類中的最終方法,屬性或下标的嘗試都會報告為編譯時錯誤。添加到擴充中的類的方法,屬性或下标也可以在擴充的定義中标記為final。

可以通過在類定義中的class關鍵字之前編寫final修飾符來将整個類标記為final 。任何将最終類子類化的嘗試都會報告為編譯時錯誤。