Swift - 繼承

繼承


一個類可以繼承另一個類的方法偿警,屬性和其它特性负间。當(dāng)一個類繼承其它類時,繼承類叫子類颖杏,被繼承類叫超類(或父類)纯陨。在 Swift 中,繼承是區(qū)分「類」與其它類型的一個基本特征留储。

在 Swift 中翼抠,類可以調(diào)用和訪問超類的方法、屬性和下標获讳,并且可以重寫這些方法阴颖,屬性和下標來優(yōu)化或修改它們的行為。Swift 會檢查你的重寫定義在超類中是否有匹配的定義丐膝,以此確保你的重寫行為是正確的量愧。

可以為類中繼承來的屬性添加屬性觀察器,這樣一來帅矗,當(dāng)屬性值改變時侠畔,類就會被通知到∷鹞睿可以為任何屬性添加屬性觀察器软棺,無論它原本被定義為存儲型屬性還是計算型屬性。

定義一個基類

不繼承于其它類的類尤勋,稱之為基類喘落。

注意

Swift 中的類并不是從一個通用的基類繼承而來的。如果你不為自己定義的類指定一個超類的話最冰,這個類就會自動成為基類瘦棋。

下面的例子定義了一個叫 Vehicle 的基類。這個基類聲明了一個名為 currentSpeed暖哨,默認值是 0.0 的存儲型屬性(屬性類型推斷為 Double)赌朋。currentSpeed 屬性的值被一個 String 類型的只讀計算型屬性 description 使用,用來創(chuàng)建對于車輛的描述篇裁。

Vehicle 基類還定義了一個名為 makeNoise 的方法沛慢。這個方法實際上不為 Vehicle 實例做任何事,但之后將會被 Vehicle 的子類定制:

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {
        // 什么也不做——因為車輛不一定會有噪音
    }
}

可以用初始化語法創(chuàng)建一個 Vehicle 的新實例达布,即類名后面跟一個空括號:

let someVehicle = Vehicle()

現(xiàn)在已經(jīng)創(chuàng)建了一個 Vehicle 的新實例团甲,你可以訪問它的 description 屬性來打印車輛的當(dāng)前速度:

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

Vehicle 類定義了一個具有通用特性的車輛類,但實際上對于它本身來說沒什么用處黍聂。為了讓它變得更加有用躺苦,還需要進一步完善它身腻,從而能夠描述一個具體類型的車輛。

子類生成

子類生成指的是在一個已有類的基礎(chǔ)上創(chuàng)建一個新的類匹厘。子類繼承超類的特性嘀趟,并且可以進一步完善。你還可以為子類添加新的特性愈诚。

為了指明某個類的超類她按,將超類名寫在子類名的后面,用冒號分隔:

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

下一個例子扰路,定義了一個叫 Bicycle 的子類尤溜,繼承自超類 Vehicle

class Bicycle: Vehicle {
    var hasBasket = false
}

新的 Bicycle 類自動繼承 Vehicle 類的所有特性倔叼,比如 currentSpeeddescription 屬性汗唱,還有 makeNoise() 方法。

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

默認情況下,你創(chuàng)建的所有新的 Bicycle 實例不會有一個籃子(即 hasBasket 屬性默認為 false)巡验。創(chuàng)建該實例之后际插,你可以為 Bicycle 實例設(shè)置 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”

子類還可以繼續(xù)被其它類繼承显设,下面的示例為 Bicycle 創(chuàng)建了一個名為 Tandem(雙人自行車)的子類:

class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}

TandemBicycle 繼承了所有的屬性與方法框弛,這又使它同時繼承了 Vehicle 的所有屬性與方法。Tandem 也增加了一個新的叫做 currentNumberOfPassengers 的存儲型屬性捕捂,默認值為 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”

重寫

子類可以為繼承來的實例方法,類方法允悦,實例屬性膝擂,類屬性,或下標提供自己定制的實現(xiàn)隙弛。我們把這種行為叫重寫架馋。

如果要重寫某個特性,你需要在重寫定義的前面加上 override 關(guān)鍵字全闷。這么做绩蜻,就表明了你是想提供一個重寫版本,而非錯誤地提供了一個相同的定義室埋。意外的重寫行為可能會導(dǎo)致不可預(yù)知的錯誤办绝,任何缺少 override 關(guān)鍵字的重寫都會在編譯時被認定為錯誤伊约。

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

訪問超類的方法屡律,屬性及下標

當(dāng)你在子類中重寫超類的方法,屬性或下標時降淮,有時在你的重寫版本中使用已經(jīng)存在的超類實現(xiàn)會大有裨益超埋。比如,你可以完善已有實現(xiàn)的行為佳鳖,或在一個繼承來的變量中存儲一個修改過的值霍殴。

在合適的地方,你可以通過使用 super 前綴來訪問超類版本的方法系吩,屬性或下標:

  • 在方法 someMethod() 的重寫實現(xiàn)中来庭,可以通過 super.someMethod() 來調(diào)用超類版本的 someMethod() 方法。

  • 在屬性 someProperty 的 getter 或 setter 的重寫實現(xiàn)中穿挨,可以通過 super.someProperty 來訪問超類版本的 someProperty 屬性月弛。

  • 在下標的重寫實現(xiàn)中,可以通過 super[someIndex] 來訪問超類版本中的相同下標科盛。

重寫方法

在子類中帽衙,你可以重寫繼承來的實例方法或類方法,提供一個定制或替代的方法實現(xiàn)贞绵。

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

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

如果你創(chuàng)建一個 Train 的新實例榨崩,并調(diào)用了它的 makeNoise() 方法谴垫,你就會發(fā)現(xiàn) Train 版本的方法被調(diào)用:

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

重寫屬性

你可以重寫繼承來的實例屬性或類型屬性,提供自己定制的 getter 和 setter蜡饵,或添加屬性觀察器弹渔,使重寫的屬性可以觀察到底層的屬性值什么時候發(fā)生改變。

重寫屬性的 Getters 和 Setters

你可以提供定制的 getter(或 setter)來重寫任何一個繼承來的屬性溯祸,無論這個屬性是存儲型還是計算型屬性肢专。子類并不知道繼承來的屬性是存儲型的還是計算型的,它只知道繼承來的屬性會有一個名字和類型焦辅。你在重寫一個屬性時博杖,必須將它的名字和類型都寫出來。這樣才能使編譯器去檢查你重寫的屬性是與超類中同名同類型的屬性相匹配的筷登。

你可以將一個繼承來的只讀屬性重寫為一個讀寫屬性剃根,只需要在重寫版本的屬性里提供 getter 和 setter 即可。但是前方,你不可以將一個繼承來的讀寫屬性重寫為一個只讀屬性狈醉。

注意

如果你在重寫屬性中提供了 setter廉油,那么你也一定要提供 getter。如果你不想在重寫版本中的 getter 里修改繼承來的屬性值苗傅,你可以直接通過 super.someProperty 來返回繼承來的值抒线,其中 someProperty 是你要重寫的屬性的名字。

以下的例子定義了一個新類渣慕,叫 Car嘶炭,它是 Vehicle 的子類。這個類引入了一個新的存儲型屬性叫做 gear逊桦,默認值為整數(shù) 1眨猎。Car 類重寫了繼承自 Vehicledescription 屬性,提供包含當(dāng)前檔位的自定義描述:

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

重寫的 description 屬性首先要調(diào)用 super.description 返回 Vehicle 類的 description 屬性强经。之后睡陪,Car 類版本的 description 在末尾增加了一些額外的文本來提供關(guān)于當(dāng)前檔位的信息。

如果你創(chuàng)建了 Car 的實例并且設(shè)置了它的 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”

重寫屬性觀察器

你可以通過重寫屬性為一個繼承來的屬性添加屬性觀察器宝穗。這樣一來户秤,無論被繼承屬性原本是如何實現(xiàn)的码秉,當(dāng)其屬性值發(fā)生改變時,你就會被通知到鸡号。關(guān)于屬性觀察器的更多內(nèi)容转砖,請看 屬性觀察器

注意

你不可以為繼承來的常量存儲型屬性或繼承來的只讀計算型屬性添加屬性觀察器鲸伴。這些屬性的值是不可以被設(shè)置的府蔗,所以,為它們提供 willSetdidSet 實現(xiàn)也是不恰當(dāng)汞窗。 此外還要注意姓赤,你不可以同時提供重寫的 setter 和重寫的屬性觀察器。如果你想觀察屬性值的變化仲吏,并且你已經(jīng)為那個屬性提供了定制的 setter不铆,那么你在 setter 中就可以觀察到任何值變化了。

下面的例子定義了一個新類叫 AutomaticCar裹唆,它是 Car 的子類誓斥。AutomaticCar 表示自動檔汽車,它可以根據(jù)當(dāng)前的速度自動選擇合適的檔位:

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

當(dāng)你設(shè)置 AutomaticCarcurrentSpeed 屬性许帐,屬性的 didSet 觀察器就會自動地設(shè)置 gear 屬性劳坑,為新的速度選擇一個合適的檔位。具體來說就是成畦,屬性觀察器將新的速度值除以 10距芬,然后向下取得最接近的整數(shù)值涝开,最后加 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 來防止它們被重寫存和,只需要在聲明關(guān)鍵字前加上 final 修飾符即可(例如:final var奕剃、final funcfinal class func 以及 final subscript)捐腿。

任何試圖對帶有 final 標記的方法纵朋、屬性或下標進行重寫的代碼,都會在編譯時會報錯茄袖。在類擴展中的方法操软,屬性或下標也可以在擴展的定義里標記為 final

可以通過在關(guān)鍵字 class 前添加 final 修飾符(final class)來將整個類標記為 final 宪祥。這樣的類是不可被繼承的聂薪,試圖繼承這樣的類會導(dǎo)致編譯報錯。


繼續(xù)閱讀 Swift - 構(gòu)造過程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝗羊,一起剝皮案震驚了整個濱河市藏澳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌耀找,老刑警劉巖翔悠,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異野芒,居然都是意外死亡蓄愁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門狞悲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撮抓,“玉大人,你說我怎么就攤上這事摇锋〉ふ” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵乱投,是天一觀的道長咽笼。 經(jīng)常有香客問我,道長戚炫,這世上最難降的妖魔是什么剑刑? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上施掏,老公的妹妹穿的比我還像新娘钮惠。我一直安慰自己,他們只是感情好七芭,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布素挽。 她就那樣靜靜地躺著,像睡著了一般狸驳。 火紅的嫁衣襯著肌膚如雪预明。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天耙箍,我揣著相機與錄音撰糠,去河邊找鬼。 笑死辩昆,一個胖子當(dāng)著我的面吹牛阅酪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播汁针,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼术辐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了施无?” 一聲冷哼從身側(cè)響起辉词,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎帆精,沒想到半個月后较屿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體隧魄,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡卓练,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了购啄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片襟企。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖狮含,靈堂內(nèi)的尸體忽然破棺而出顽悼,到底是詐尸還是另有隱情,我是刑警寧澤几迄,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布蔚龙,位于F島的核電站,受9級特大地震影響映胁,放射性物質(zhì)發(fā)生泄漏木羹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坑填。 院中可真熱鬧抛人,春花似錦、人聲如沸脐瑰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苍在。三九已至绝页,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寂恬,已是汗流浹背抒寂。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掠剑,地道東北人屈芜。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像朴译,于是被迫代替她去往敵國和親井佑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一個類可以繼承另一個類的方法眠寿,屬性和其它特性躬翁。當(dāng)一個類繼承其它類時,繼承類叫子類盯拱,被繼承類叫超類(或父類)盒发。在 S...
    CDLOG閱讀 70評論 0 0
  • 一個類可以繼承另一個類的方法,屬性和其它特性狡逢。當(dāng)一個類繼承其它類時宁舰,繼承類叫子類,被繼承類叫超類(或父類)奢浑。在 S...
    小驢拉磨閱讀 178評論 0 0
  • 中文文檔 一個類可以繼承另一個類的方法蛮艰,屬性和其它特性。當(dāng)一個類繼承其它類時雀彼,繼承類叫子類壤蚜,被繼承類叫超類(或父類...
    伯wen閱讀 231評論 0 0
  • 一個類可以從另外一個類中繼承方法,屬性或者其它的一些特性。當(dāng)一個類繼承于另外一個類時草则,這個繼承的類叫子類钢拧,被繼承的...
    泥孩兒0107閱讀 1,928評論 0 1
  • 一個類可以繼承另一個類的方法,屬性和其它特性炕横。 當(dāng)一個類繼承其它類時源内,繼承類叫子類,被繼承類叫超類(或父類)份殿。 在...
    DevXue閱讀 104評論 0 0