Swift 繼承 權限 型別

繼承

子類別可以繼承到父類別的屬性或方法

類別繼承的語法格式
SuperBaby 物件可使用來自父類別的age 屬性 和 sleep ( ) 方法

所謂 屬性繼承 包含了 stored property computed property 和 property observer 繼承 但不允許多重繼承 這點跟Obj-C 一樣

一次只能繼承一個類別
方法和屬性的覆寫 override

覆寫的功能是重新定義父類別的方法跟屬性

override sleep function
重新定義繼承而來的方法一定要加override

而如果想呼叫原本父類別的方法 可以使用super.方法

利用super呼叫父類別 Baby 裡定義的 sleep 方法

如上圖所示 Superbaby 繼承了Baby的 sleep用了super.sleep( )並加上了自己的“吃飽繼續睡”

computed property 也可透過 override重新定義 只不過他只在屬性存取執行

override computed property centerX
存取 centerX將執行 SpecialSquare 裡定義的程式碼

在覆寫 computed property 時 如果父類別有定義 get 和 set 那麼覆寫也要同時定義 但如果父類別只定義get 子類別是可以get set都定義的

除了computed property 子類別也可將繼承而來stored property 以 computed property 覆寫 以改變子類別物件存取屬性時的行為 如下圖

將繼承自Baby 的 name 以 computed property 覆寫

set 的存在只是為了避免compile error 因為Baby的 name 原本是可讀可寫的 stored property 覆寫的 computed property 也一定要可讀可寫 同時定義 set 和get

除了方法和屬性 property observer 也可以覆寫

覆寫屬性name 的 observer
忘記了property observer 複習一下
willSet(新的變數值) 將在屬性即將設定時被呼叫
didSet(舊的變數值) 將在屬性已設定被呼叫

Observer 跟上面的屬性覆寫不同 他是加成的效果 當我們override observer時 其實就是多增加一段屬性內容被設定時觸發的程式碼 而原先被觸發的程式碼依然會執行

觸發順序:

子類別的willSet->父類別的willSet->父類別的didSet->子類別的didSet

子類別隨時都可利用override 添加 property observer 不管是stored property 或 computed property 或 父類別屬性有無定義 observer

SleepingBeauty 覆寫stored property name 添加 observer
SpecialSquare覆寫 computed property centerX 為它添加 observer

當SquareSquare 物件的centerX被設定時 方法觸發的順序如下:

1.子類別的willSet

2.父類別的set

3.子類別的didSet

然後我們再新增繼承自SpecialSquare的SpecialSquare2 這一次換成重新定義centerX的 set和 get

SpecialSquare2重新定義centerX的 get和 set

console只有印出“設定SpecialSquare2的centerX” 因為我們設定的是SpecialSquare2的centerX

SpecialSquare2和Square的centerX是不同的東西

SpecialSquare的observer 只會在 Square 的 centerX 被設定時觸發

如果我們想呼叫 Square 的 centerX 可以用 super 如下圖

於 SpecialSquare2 裡設定 super.centerX 將存取 Square 的 centerX
防止被覆寫的final

在類別宣告前加上final

宣告為final 的類別 不允許被繼承

在屬性前加上final

在方法前加上final

先初始子類別的 magic 再初始父類別的 age

magic 在Superbaby 的initializer 裡初始 , age 在Baby 的initializer 裡初始,符合子類別得先完成自己屬性的初始後, 才能進行父類別屬性的初始

不能先初始父類別的屬性 再初始子類別的屬性 會 compiler error

至於為什麼要先呼叫子類別,才不會有安全問題,如下圖

呼叫父類別時,它內部還有一個function,而覆寫後的function 裡面的self.magic還未被宣告 ,造成錯誤

物件建立初始化的過程

階段一 由子類別的initializer 一路往上進行每個父類別的initializer

過程裡一定得先將自己的屬性初始化後 才能呼叫父類別的initializer 當階段一完成時 物件的所有屬性皆已完成初始

階段二 物件的所有屬性都完成初始 所以可以對屬性做任何存取 或者呼叫其他的方法

在Swift裡 initializer分成兩種

designated initializer:每個類別都要有一個designated initializer ,其負責完成類別裡所有屬性的初始

convenience initializer:特徵為init前加上convenience,類別裡不見得要宣告,主要好處在於提供使用者更方便建立物件的方法,比方接受較少的參數,使用者建立物件時只需要傳入部分屬性的參數值,如下圖

在convenience initializer init(name:String )裡呼叫 designated initializer init(age:Int,name:String)完成所有屬性的初始

convenience initializer 的好處在於我們只需傳入名字“peter” 但最後生成的物件卻連age也被正確初始

initializer 的繼承

Swift 預設並不會繼承父類別的initializer, 除非遇到以下兩種特殊情況

情況一:子類別沒有定義任何designated initializer

情況二:如果滿足情況一,或子類別覆寫了所有父類別所有的designated initializer,它將繼承父類別的convenience initializer

SuperBaby順利繼承父類別Baby的designated initializer,滿足情況一
SuperBaby順利繼承父類別的convenience initializer

由於SuperBaby沒有定義任何designated initializer,滿足情況二,順利繼承

SuperBaby 順利繼承父類別Baby的 convenience initializer

SuperBaby覆寫所有Baby的designated initializer,滿足情況二,順利繼承父類別的convenience initializer,因此我們可以用SuperBaby()來建立物件

(覆寫designated initializer 需要加override,convenience initializer 不用)

required initializer
子類別有定義init的情況下,不會呼叫父類別的init

而如果我們想避免這種情況可以使用required initializer

SuperBaby一定要定義父類別裡加了 required 的 init( )
SuperBaby 定義父類別加了required的 init( )時,也要加上required