Objective c 知識總結 繼承

半紙淵發表於2017-12-14

知識盲點:

  • OOP 物件導向程式設計(Object Oriented Programming,OOP)
  • Unified Modeling Language (UML)
  • Inheritance 繼承
  • Syntax 語法
  • 重構(Refactoring):Moving and simplifying code this way is called refactoring, a subject that is quite trendy in the OOP community.(移動或簡化程式碼稱為重構)When you refactor, you move code around to improve the architecture, as we did here to eliminate duplicate code, without changing the code’s behavior or results.(不改變程式碼的最終效果)
  • polymorphism 多型

知識點:

  • 為什麼要使用繼承?
  • 繼承在Objective-C中的語法表示?

  • 為什麼要使用繼承?
  • 假設有兩個類 圓、方形 圓(.h):
    Objective c 知識總結    繼承
    方形(.h):
    Objective c 知識總結    繼承
    觀察發現,它們屬性和方法宣告是相同的,都有 填充色(fillcolor)、尺寸+位置(bounds)、繪製方法; 如此相同的宣告,除了類名不同,其它都一樣?那麼可否把它們的宣告封裝(抽象)起來,但類名(具體細節)又可以不一樣? 先儲存這種疑問,來看看(.m)檔案。 圓(.m):
    Objective c 知識總結    繼承
    Objective c 知識總結    繼承
    方形(.m):
    Objective c 知識總結    繼承
    Objective c 知識總結    繼承
    觀察發現,圓和方形的 setFillColor: 和 setBounds: 方法的實現是一樣的,唯一的不同就是它們的繪製方法 draw: ; 通過觀察分析可以得知,如果要把圓、方形封裝起來,那麼就要保證具體的實現可以有不一樣(draw:)方法;簡單來說就是,封裝(抽象)不對細節進行限制,只對宣告進行限制,就是隻告訴你叫什麼,不告訴你是什麼,要確定是什麼,根據不同的型別(圓或者方形)來確定。 結:我們都知道的,圓和方形都是幾何圖形,而物件導向程式設計,就是對現實世界的抽象,而圓和方形的抽象就是幾何圖形;換種方式描述就是,幾何圖形是圓、方形的父集(父親),圓、方形是幾何的子集(子女)。 抽象過程:
    Objective c 知識總結    繼承
    Objective c 知識總結    繼承
    繼承 :Inheritance in OOP means that a class acquires features from another class, its parent or superclass.(一個類(子類)的特性(屬性+方法+協議......)來源於另一個類(父類))
  • 繼承在Objective-C中的語法表示? 首先,通過上面的分析,圓、方形的特性可以由幾何圖形來提供,也就是說圓、方形是可以繼承於幾何圖形的。
    Objective c 知識總結    繼承
    分析程式碼: @interface 子類 : 父類 // 新特性 @end @interface 和 @end 是一對,不能拆開前者表明繼承的開始,後者表明繼承的結束; 子類,就是新建立的類的類名(Circle / Rectangle); 父類,要繼承的類(Shape); //新特性:可以定義自己的特性 上面 程式碼的意思:Circle/Rectangle繼承於Shape(擁有Shape的特性); Shape(.h):
    Objective c 知識總結    繼承
    Shape(.m):
    Objective c 知識總結    繼承
    Objective c 知識總結    繼承
    程式碼分析: @interface Shape : NSObject ,NSObject是 Cocoa Touch 框架的根類,所有類的父類; {...},是宣告例項變數; @implementaion 和 @end 是一對,表明對方法的實現; 觀察 Shape 的(.m)檔案可以發現,只有 draw 方法是空的,因為我們清楚圓和方形的繪製方式是不同的(相當於等待子類自己去實現),而顏色填充和尺寸位置的表現方式是一樣的; 圓的繪製方法:
    Objective c 知識總結    繼承
    方形的繪製方法:
    Objective c 知識總結    繼承

疑問:

  • 一個類可以繼承多個父類嗎?
  • 子類可以直接使用父類的特性?
  • 子類重新實現了繪製方法,那麼編譯器會優先使用父類的方法還是子類的呢?
  • 子類可以修改父類的特性嗎?

一些繼承的術語:

  • superclass(超類):the class you’re inheriting from.(你所繼承的類,幾何圖形)
  • Parent class(父類),superclass 的另一種說法
  • subclass (子類):the class doing the inheriting(做繼承這個行為的類,圓、方形)
  • Child class (孩子類):subclass 的另一種說法
  • override (重寫):an inherited method when you want to change its implementation(重新實現繼承而來的方法)

疑問解答: 1.Objective-C不能實現多繼承,就是說(class : class1,class2...)是不允許的; 2.父類的例項變數能否被子類使用,取決於例項變數的許可權修飾符

Objective c 知識總結    繼承
預設是@protected,子類可以繼承父類的例項變數,但是是否可以訪問,就看許可權修飾符; 如果是使用屬性@property進行宣告的,就要檢視相應的屬性修飾符; 3.方法排程優先順序: When code sends a message, the Objective-C method dispatcher searches for the method in the current class. If the dispatcher doesn’t find the method in the class of the object receiving the message, it looks at the object’s superclasses.(當一個類傳送訊息的時候,排程器會首先從當前類中的方法列表中查詢相應的訊息方法,如果發現當前沒有找到,就會進入到當前類的父類中進行查詢如果有就執行,如果沒有就繼續向父類查詢直到找到 NSObject 類還是沒有的話,就直接報錯。) 例子: 假設給圓這個類的例項設定顏色如下: [Circle setFillColor:kRedColor]; 未繼承Shape
Objective c 知識總結    繼承
繼承了Shape
Objective c 知識總結    繼承
4.子類可以新增新的例項變數 假設建立一個新類:RoundedRectangle(圓角矩形) 首先它是幾何圖形,也是矩形(方形),但是比矩形多了一個圓角;所以它可以直接繼承幾何圖形,也可以繼承矩形;
Objective c 知識總結    繼承
建立一個 RoundedRectangle 物件例項,它的例項變數在記憶體的分佈是:
Objective c 知識總結    繼承
內容分析: “isa”:The NSObject instance variable is called isa because inheritance sets up an “is a” relationship between the subclass and the superclass; that is, a Rectangle is a Shape, and a Circleis a Shape. Code that uses a Shape can also use a Rectangle or Circle instead.(isa意指 “是一個” ,如:圓是一個幾何圖形,矩形是一個幾何圖形,表明一種包含關係);isa 是 NSObject 的例項變數; “fillcolor bounds”:Shape 的例項變數,因為 RoundedRectangle 繼承了 Shape 所以有這兩個特性,而 fillcolor 是先於 bounds 被定義的,所以它處於上方; “radius”:圓角是 RoundedRectangle 這個類特有的特性,因為最後被定義所以處於最後的位置; 注:每一個例項變數都有一個隱藏的例項(元類的例項) self 完整的圖是:
Objective c 知識總結    繼承
內容分析: 所有的例項變數是分配在一塊記憶體區域中的,而且是有序的、每一個例項變數的記憶體大小是已經固定的; self 就是指向記憶體區域的首地址,只要根據各個例項變數的記憶體大小進行移位就可以正常訪問到每一個例項變數;(The compiler works its magic by using a “base plus offset” (首地址+偏移量)mechanism. Given the base address of an object—that is, the memory location of the first byte of the first instance variable—the compiler can find all other instance variables by adding an offset to that address.) ???問題:This does lead to problems over time. These offsets are now hard-coded into the program generated by the compiler. Even if Apple’s engineers wanted to add another instance variable to NSObject, they couldn’t, because that would change all of the instance variable offsets. This is called the fragile base class problem(脆弱的基類問題). Apple has fixed this problem with the new 64-bit Objective-C runtime introduced with Leopard, which uses indirection for determining ivar locations. 從兩張圖可以知道,當一個類的例項化後,它的例項物件在記憶體的位置(地址)是固定的,而且大小也是固定的,也就是 self 每一次的偏移量也是固定的; 那麼問題來了,假設我現在又想增加一個例項變數呢,如果是新增在 radius 的後面,記憶體的地址沒有發生變化,如果新增在 fillcolor / bounds / radius 的中間呢?那麼記憶體地址就發生了改變, self 的每一交偏移量就發生了改變; 所以在後來蘋果使用了間接的手段對 ivar (例項變數)進行記憶體測定,從而杜絕例項物件在初始化化後例項變數頻繁修改所引起的記憶體變化; 5.修改(重寫)父類的方法(特性) When classes such as Circle and Rectangle implement their own draw methods, we say that they have overridden the draw method. 在文章的開始時,就有 Circle / Rectangle 兩個類,它們都是 Shape 的子類,而且它們都實現了自己的 draw 方法,而這種行為就是重寫(重新實現 draw 方法); 注:When a draw message is sent to a circle object, the method dispatcher runs the overridden method—Circle’s implementation of draw. Any implementation of draw defined by a superclass, such as Shape, is completely ignored.(由於排程優先順序的存在,排程會先從子類開始到根類,而子類一旦有相應的訊息方法,那麼就會直接排程而不會再進行深一層的查詢(繼承鏈),會直接忽略父類的相同方法) ???問題:假設現在要把所有建立的圓例項物件的紅色填充修改為綠色填充? 第一種就是,每一個例項物件都呼叫 [ Circle setFillColor:kGreenColor ];直接進行設定(實際上是呼叫了父類的顏色填充方法,因為父類的顏色填充方法沒有顏色判斷功能,只是單純的顏色填充,所以導致每一個例項物件都要自己去設定顏色,而且 Circlr 還無法保證設定是否符合要求); 第二種就是, Circle 類自己寫一個設定顏色的方法,只要不是綠色的都改成綠色,再進行顏色填充;(重寫 父類方法) 看程式碼:
Objective c 知識總結    繼承
程式碼分析: "super setFillColor":這句程式碼就是使用父類的填充顏色方法;當然自己重新寫也可以; 重寫的方法(setFillColor:)的排程過程:
Objective c 知識總結    繼承
注:如果重寫了父類的方法,建議還是呼叫 [ super setFillColor:c ];這樣可以保證父類做完它應該做的事,避免不必要的錯誤。

相關文章