引言
繼續(xù)學(xué)習(xí)Swift文檔驱犹,從上一章節(jié):下標(biāo)雄驹,我們學(xué)習(xí)了Swift下標(biāo)相關(guān)的內(nèi)容医舆,如下標(biāo)語法象缀、下標(biāo)用法爷速、下標(biāo)選項和類型下標(biāo)等這些內(nèi)容⊙胄牵現(xiàn)在,我們學(xué)習(xí)Swift的繼承相關(guān)的內(nèi)容遍希。由于篇幅較長等曼,這里分篇來記錄里烦,接下來凿蒜,F(xiàn)ighting!
熟悉這一章節(jié)的朋友可以直接跳過下一章節(jié):初始化
繼承
一個類可以從另一個類繼承方法胁黑,屬性和其他特征废封。 當(dāng)一個類從另一個類繼承時丧蘸,繼承的類稱為子類漂洋,而其繼承的類稱為其父類。 繼承是一種基本行為力喷,可將Swift中的類與其他類型區(qū)分開刽漂。
Swift中的類可以調(diào)用和訪問屬于其父類的方法,屬性和下標(biāo)弟孟,并可以提供這些方法贝咙,重寫屬性和下標(biāo)以完善或修改其行為。 Swift通過檢查覆蓋定義是否具有匹配的父類定義來幫助確保覆蓋是正確的拂募。
類還可以將屬性觀察器添加到繼承的屬性中庭猩,以便在屬性值更改時得到通知。 可以將屬性觀察器添加到任何屬性陈症,而不管其最初是定義為存儲屬性還是計算屬性蔼水。
1 定義基類
任何不從另一個類繼承的類都稱為基類。
注意
Swift類不能從通用基類繼承录肯。 您沒有指定父類而定義的類將自動成為基類供您構(gòu)建趴腋。
下面的示例定義了一個稱為Vehicle的基類。 該基類定義了一個稱為currentSpeed的存儲屬性论咏,默認(rèn)值為0.0(推斷屬性類型為Double)于样。 currentSpeed屬性的值由一個稱為description的只讀計算出的String屬性用于創(chuàng)建車輛的描述。
Vehicle基類還定義了一個稱為makeNoise的方法潘靖。 此方法實際上不對基礎(chǔ)Vehicle實例執(zhí)行任何操作穿剖,但稍后將由Vehicle的子類自定義:
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
}
}
使用初始化器語法創(chuàng)建一個Vehicle的新實例,該實例被寫為類型名稱卦溢,后跟空括號:
let someVehicle = Vehicle()
創(chuàng)建新的Vehicle實例后糊余,您可以訪問其description屬性秀又,以打印出人類可以理解的車輛當(dāng)前速度的描述:
print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour
Vehicle類定義了任意車輛的共同特征,但其本身并沒有太多用途贬芥。 為了使其更有用吐辙,您需要對其進(jìn)行改進(jìn)以描述更多特定類型的車輛。
2 子類
子類化是在現(xiàn)有類的基礎(chǔ)上建立新類的行為蘸劈。 子類繼承現(xiàn)有類的特征昏苏,然后可以對其進(jìn)行優(yōu)化。 您還可以向子類添加新特征威沫。
要表明子類具有父類贤惯,請在父類名稱之前寫上子類名稱,并用冒號分隔:
class SomeSubclass: SomeSuperclass {
// subclass definition goes here
}
下面的示例定義了一個名為Bicycle的子類棒掠,并帶有Vehicle的父類:
class Bicycle: Vehicle {
var hasBasket = false
}
新的Bicycle類自動獲得了Vehicle的所有特征孵构,例如currentSpeed和description屬性以及makeNoise()方法。
除其繼承的特征外烟很,Bicycle類還定義了一個新的存儲屬性hasBasket颈墅,其默認(rèn)值為false(為該屬性推斷為Bool類型)。
默認(rèn)情況下雾袱,您創(chuàng)建的任何新Bicycle實例都沒有籃子恤筛。 創(chuàng)建特定的Bicycle實例后,可以將hasBasket屬性設(shè)置為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
子類本身可以被子類化毒坛。 下一個示例為稱為“雙人”的兩人座自行車創(chuàng)建Bicycle的子類:
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
}
Tandem繼承了Bicycle的所有屬性和方法,而后者又繼承了Vehicle的所有屬性和方法僻族。 Tandem子類還添加了一個名為currentNumberOfPassengers的新存儲屬性粘驰,默認(rèn)值為0。
如果創(chuàng)建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 重寫
子類可以提供其自己的實例方法,類型方法度秘,實例屬性顶伞,類型屬性或下標(biāo)的自定義實現(xiàn),否則該實例方法將從超類繼承剑梳。 這稱為重寫唆貌。
要重寫原本會被繼承的特征,請在您的重寫定義前添加override關(guān)鍵字垢乙。 這樣做可以明確您打算提供替代锨咙,并且沒有錯誤地提供匹配的定義。 偶然的重寫可能會導(dǎo)致意外的行為追逮,并且在編譯代碼時酪刀,任何不帶有override關(guān)鍵字的替代都會被診斷為錯誤粹舵。
Override關(guān)鍵字還會提示Swift編譯器檢查您的重寫類的父類(或其父類之一)是否具有與您為該替代提供的聲明相匹配的聲明。 此檢查可確保您的重寫定義正確骂倘。
3.1 訪問子類的方法眼滤、屬性和下標(biāo)
當(dāng)為子類提供方法,屬性或下標(biāo)替代時历涝,將現(xiàn)有的超類實現(xiàn)用作替代的一部分有時會很有用诅需。 例如,您可以優(yōu)化該現(xiàn)有實現(xiàn)的行為荧库,或者將修改后的值存儲在現(xiàn)有的繼承變量中堰塌。
在適當(dāng)?shù)那闆r下,您可以使用super前綴訪問方法电爹,屬性或下標(biāo)的超類版本:
- 名稱為someMethod()的重寫方法可以通過在重寫方法實現(xiàn)中調(diào)用super.someMethod()來調(diào)用someMethod()的父類方法蔫仙。
- 重寫的名稱為someProperty的屬性可以在重寫的getter或setter實現(xiàn)中以super.someProperty的方式訪問someProperty的父類屬性料睛。
- someIndex的重寫下標(biāo)可以從重寫下標(biāo)實現(xiàn)中訪問與super [someIndex]相同的下標(biāo)的父類下標(biāo)丐箩。
3.2 重寫方法
您可以重寫繼承的實例或類型方法,以在子類中提供該方法的定制或替代實現(xiàn)恤煞。
以下示例定義了一個名為Train的Vehicle的新子類屎勘,該子類重寫Train從Vehicle繼承的makeNoise()方法:
class Train: Vehicle {
override func makeNoise() {
print("Choo Choo")
}
}
如果創(chuàng)建一個Train的新實例并調(diào)用其makeNoise()方法,則可以看到該方法的Train子類版本稱為:
let train = Train()
train.makeNoise()
// Prints "Choo Choo"
3.3 重寫屬性
您可以重寫繼承的實例或類型屬性居扒,以為該屬性提供自己的自定義getter和setter概漱,或添加屬性觀察器以使重寫的屬性能夠在基礎(chǔ)屬性值更改時進(jìn)行觀察。
重寫屬性的Getters和Setters
您可以提供一個自定義getter(如果合適的話喜喂,可以使用setter)來重寫任何繼承的屬性瓤摧,而不管該繼承的屬性是在源上實現(xiàn)為存儲屬性還是計算屬性。 子類不知道繼承屬性的存儲或計算性質(zhì)玉吁,它僅知道繼承屬性具有特定名稱和類型照弥。 您必須始終聲明要重寫的屬性的名稱和類型,以使編譯器能夠檢查您的重寫是否與具有相同名稱和類型的父類屬性匹配进副。
通過在子類屬性重寫中同時提供getter和setter这揣,可以將繼承的只讀屬性呈現(xiàn)為讀寫屬性。 但是影斑,您不能將繼承的讀寫屬性表示為只讀屬性给赞。
注意
如果在屬性替代中提供了一個setter,則還必須為該替代提供一個getter矫户。 如果您不想在重寫的getter中修改繼承的屬性的值片迅,則可以通過從getter返回super.someProperty來傳遞繼承的值,其中someProperty是您要重寫的屬性的名稱皆辽。
以下示例定義了一個名為Car的新類柑蛇,它是Vehicle的子類罐旗。 Car類引入了一個稱為gear的新存儲屬性,其默認(rèn)整數(shù)值為1唯蝶。Car類還覆蓋了它從Vehicle繼承的description屬性九秀,以提供包括當(dāng)前gear的自定義描述:
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)"
}
}
對description屬性的重寫是通過調(diào)用super.description開始的,super.description返回Vehicle類的description屬性粘我。 然后鼓蜒,汽車類的描述版本會在此描述的末尾添加一些額外的文字,以提供有關(guān)當(dāng)前裝備的信息征字。
如果創(chuàng)建Car類的實例并設(shè)置其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
重寫屬性監(jiān)聽
您可以使用屬性重寫將屬性觀察器添加到繼承的屬性。 這使您可以在繼承屬性的值更改時得到通知匙姜,而無論該屬性最初是如何實現(xiàn)的畅厢。 有關(guān)屬性觀察器的更多信息,請參見Property Observers氮昧。
注意
您不能將屬性觀察器添加到繼承的常量存儲屬性或繼承的只讀計算屬性框杜。 這些屬性的值無法設(shè)置,因此不建議將willSet或didSet實現(xiàn)作為覆蓋的一部分提供袖肥。
還要注意咪辱,您不能為同一屬性同時提供覆蓋設(shè)置器和覆蓋屬性觀察器。 如果您想觀察屬性值的變化椎组,并且已經(jīng)在為該屬性提供自定義設(shè)置器油狂,則可以簡單地觀察自定義設(shè)置器中的任何值更改。
下面的示例定義一個名為AutomaticCar的新類寸癌,它是Car的子類专筷。 AutomaticCar類代表具有自動變速箱的汽車,該變速箱會根據(jù)當(dāng)前速度自動選擇要使用的檔位:
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}
每當(dāng)您設(shè)置AutomaticCar實例的currentSpeed屬性時蒸苇,該屬性的didSet觀察器都會將該實例的gear屬性設(shè)置為新速度的適當(dāng)齒輪磷蛹。 具體來說,屬性觀察者選擇的齒輪是新的currentSpeed值除以10填渠,四舍五入到最接近的整數(shù)加1弦聂。35.0的速度產(chǎn)生4的齒輪:
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4
4 防止重寫
您可以通過將方法,屬性或下標(biāo)標(biāo)記為final來防止其被重寫氛什。 為此莺葫,可以在方法,屬性或下標(biāo)的Introductionr關(guān)鍵字(例如final var枪眉,final func捺檬,final class func和final下標(biāo))之前編寫final修飾符。
嘗試重寫子類中的最終方法贸铜,屬性或下標(biāo)的任何嘗試都將報告為編譯時錯誤堡纬。 您在擴(kuò)展程序的類中添加的方法聂受,屬性或下標(biāo)也可以在擴(kuò)展程序的定義中標(biāo)記為final。
您可以通過在類定義中的class關(guān)鍵字之前編寫final修飾符烤镐,將整個類標(biāo)記為(final class)蛋济。 任何嘗試將最終類作為子類的嘗試都將報告為編譯時錯誤。
總結(jié)
這一章節(jié)主要講的是:
- 繼承的作用:可以繼承父類定義的屬性炮叶、方法和下標(biāo)碗旅,以擴(kuò)展自定義的功能。
- 沒有從父類繼承的類都是基類镜悉,在基類里面定義一些基本的屬性和方法祟辟,以提供子類來擴(kuò)展。
- 使用override關(guān)鍵詞修飾父類的屬性或方法來重寫父類里面實現(xiàn)的功能侣肄《希可以重寫屬性的Getters和Setters担猛、屬性監(jiān)聽留量。
- 使用final關(guān)鍵詞修飾可以防止重寫雄人。
好了,有收獲的朋友麻煩給個鼓勵哦缰贝,謝謝啦~
參考文檔: Swift - Inheritance