繼承(Inheritance)
- 值類型(枚舉、結構體)不支持繼承,只有類支持繼承
- 沒有父類的類,稱爲:基類
- Swift並沒有像OC、Java那樣的規定:任何類最終都要繼承自某個基類
- 子類可以重寫父類的下標、方法、屬性,重寫必須加上override關鍵字
內存結構
Dog繼承自Animal,也就擁有了age屬性, Dog實際佔用的內存空間是32個字節,其中指針類型8個字節,引用計數8個字節,age8個字節,weight8個字節
ErHa繼承Dog,也就擁有了age,weight和iq三個屬性,ErHa實際佔用的內存空間是48個字節,其中指針類型8個字節,引用計數8個字節,age8個字節,weight8個字,iq8個字節,因爲要內存對齊,都要是16的倍數,所以還有8個空字節
重寫實例方法、下標
下面的代碼屬於父類指針指向子類對象,類似於OC的多態,anim調用的方法還是Cat的方法
重寫類型方法、下標
- 被class修飾的類型方法、下標,允許被子類重寫
- 被static修飾的類型方法、下標,不允許被子類重寫
但是如果此時speak方法寫成 static類型,它的子類whiteCar是不能重寫speak方法的,會報錯,如下圖:
重寫屬性注意點
- 子類可以將父類的屬性(存儲、計算)重寫爲計算屬性
- 子類不可以將父類屬性重寫爲存儲屬性
- 只能重寫var屬性,不能重寫let屬性(因爲子類會涉及到修改屬性,let不允許修改,所以不能重寫let)
- 重寫時,屬性名、類型要一致
- 子類重寫後的屬性權限 不能小於 父類屬性的權限
- 如果父類屬性是隻讀的,那麼子類重寫後的屬性可以是隻讀的、也可以是可讀寫的
- 如果父類屬性是可讀寫的,那麼子類重寫後的屬性也必須是可讀寫的
重寫實例屬性
重點提示:雖然SubCircle裏的radius寫成了計算屬性,但是subCircle仍然需要開闢8個字節的內存空間存儲radius,總之一句話,從父類繼承過來的存儲屬性,都有存儲空間,子類通過super關鍵字訪問存儲空間,如果你不使用super,如下圖:
這種寫法會造成死循環:因爲get裏的radius可以看作self.radius,這會造成在SubCircle裏不斷調用它的radius,造成死循環。
重寫類型屬性
- 被class修飾的計算類型屬性,可以被子類重寫
- 被static修飾的類型屬性(存儲、計算),不可以被子類重寫
- class不可以修飾存儲類型屬性(static可以修飾存儲類型屬性),所以更不可能被子類重寫,如下圖
屬性觀察器
可以在子類中爲父類屬性(除了只讀計算屬性、let屬性)增加屬性觀察器
- 爲存儲屬性添加屬性觀察器
- 父類和子類同時有屬性觀察器
注意:這裏走circlr.radius = 10時會先走Circle didsetRadius,再走SubCircle didSetRadius,因爲是在父類賦值,所以先走父類的完成賦值。
- 給計算屬性(包括類計算屬性和實例計算屬性)添加屬性觀察器,要注意,正常情況下在一個類中不能給計算屬性加屬性觀察器(set,get與willset,didSet不能共存),但是可以通過子類給父類的計算屬性添加屬性觀察器
- 類計算屬性
2. 實例計算屬性
注意:從上圖的輸出順序可以看到,會先走Circle getRadius(也就是Circle的get),這是因爲會首先獲得Circle的oldValue的值,然後走SubCircle的WillSet,接下來走Circle的set,在最後走入SubCircle的didSet的時候,會首先獲得radius的值,所以會先走Circle的getRadius,最後走SubCircle didSetRadius。
final
- 被final修飾的方法、下標、屬性,禁止被重寫,會報錯如下圖
- 被final修飾的類,禁止被繼承,會報錯如下圖