Swift學習(十二):繼承(內存結構,override重寫,多態,屬性觀察器,final)

繼承(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)
  • 重寫時,屬性名、類型要一致
  • 子類重寫後的屬性權限 不能小於 父類屬性的權限
  1. 如果父類屬性是隻讀的,那麼子類重寫後的屬性可以是隻讀的、也可以是可讀寫的 
  2. 如果父類屬性是可讀寫的,那麼子類重寫後的屬性也必須是可讀寫的

重寫實例屬性

 

重點提示:雖然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不能共存),但是可以通過子類給父類的計算屬性添加屬性觀察器
  1. 類計算屬性

     2.   實例計算屬性

注意:從上圖的輸出順序可以看到,會先走Circle getRadius(也就是Circle的get),這是因爲會首先獲得Circle的oldValue的值,然後走SubCircle的WillSet,接下來走Circle的set,在最後走入SubCircle的didSet的時候,會首先獲得radius的值,所以會先走Circle的getRadius,最後走SubCircle didSetRadius。


final

  • 被final修飾的方法、下標、屬性,禁止被重寫,會報錯如下圖

  • 被final修飾的類,禁止被繼承,會報錯如下圖

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章