《objective-c基礎教程》學習筆記(五)—— 繼承方法


  在上一篇博文中,我們將原先的純C語言代碼,編寫成了用Objective-C(后面直接縮寫成OC)的寫法。使得代碼在易讀性上有明顯提升,結構也更清晰。同時,也對面向對象的概念有了進一步的介紹和加深。

  但是,通過上一個例子,我們發現代碼的冗余還是很大。像Circle,Rectangle和Egg的定義和實現方法幾乎代碼都是基本相同,只有個別地方不同。那么,有什么好方法來優化這些代碼呢?今天這篇博文的重點就是要介紹繼承這個方法,它將會有效的解決上面說的這個問題。

  正如你從親生父母那里繼承一些特性(頭發的顏色,鼻子的形狀等)一樣,面向對象中的繼承表明一個類從另外一個類——它的父類或超類(另一種叫法)中獲取了某些特性。也就是說,Circle,Rectangle和Egg是從Shape類繼承而來的,因此它們將獲得Shape類的屬性。

  那么,首先先給大家介紹下,在OC中,繼承的語法格式。其實,在之前幾篇博文中已經看到。聲明一個類的時候,@interface Circle :NSObject。這里的冒號,就是繼承的標示符,冒號后面的NSObject就是要繼承的類,也就是說是父類(使用Cocoa框架的時候,要繼承)。注:在OC中,不支持多繼承

  好了,介紹了基本的繼承的知識。接下來,我們就開始動手修改代碼吧。我們的思路是:先定義一個總的Shape父類,定義好方法和屬性,然后繼承父類。

 1 #import <Foundation/Foundation.h>
 2 /* 1. enum 枚舉類型 */
 3 //定義繪制圖形的類型: 圓形,矩形,橢圓形
 4 typedef enum{
 5     kCircle,
 6     kRectangle,
 7     kEgg
 8 } ShapeType;
 9 
10 //定義繪制圖形的顏色: 紅色,綠色和藍色
11 typedef enum{
12     kRedColor,
13     kGreenColor,
14     kBlueColor
15 } ShapeColor;
16 
17 /* 2. struct 結構體 */
18 //定義圖形的基本屬性
19 typedef struct{
20     int x, y, width, height;
21 } ShapeRect;
22 
23 NSString *colorName (ShapeColor fillColor)
24 {
25     switch(fillColor)
26     {
27         case kRedColor:
28             return @"red";
29             break;
30         case kGreenColor:
31             return @"green";
32             break;
33         case kBlueColor:
34             return @"blue";
35             break;
36     }
37 }
38 
39 /* 3. 定義Shape父類*/
40 @interface Shape: NSObject{
41     ShapeColor fillColor;
42     ShapeRect bounds;
43 }
44 -(void) setFillColor:(ShapeColor) fillColor;
45 -(void) setBounds:(ShapeRect) bounds;
46 -(void) draw;
47 @end //Shape
48 
49 /* 實現Shape父類 */
50 @implementation Shape
51 -(void) setFillColor:(ShapeColor) c
52 {
53     fillColor = c;
54 }
55 -(void) setBounds:(ShapeRect) b
56 {
57     bounds = b;
58 }
59 -(void) draw{
60 }
61 @end

  雖然draw方法什么功能也沒實現,但是還是需要定義。以便Shape的所有子類可以通過它去實現各自的方法。

  然后,我們分別定義Circle,Rectangle和Egg子類:

 1 /*定義Circle,繼承Shape父類*/
 2 @interface Circle: Shape
 3 @end
 4 
 5 /*定義Rectangle,繼承Shape父類*/
 6 @interface Rectangle: Shape
 7 @end
 8 
 9 /*定義Egg,繼承Shape父類*/
10 @interface Egg: Shape
11 @end

  接下來,對子類的draw方法進行實現,代碼如下:

 1 @implementation Circle
 2 -(void) draw
 3 {
 4     NSLog(@"drawing a circle at (%d %d %d %d) in %@",
 5           bounds.x,
 6           bounds.y,
 7           bounds.height,
 8           bounds.width,
 9           colorName(fillColor));
10 }
11 @end
12 
13 @implementation Rectangle
14 -(void) draw
15 {
16     NSLog(@"drawing a rectangle at (%d %d %d %d) in %@",
17           bounds.x,
18           bounds.y,
19           bounds.height,
20           bounds.width,
21           colorName(fillColor));
22 }
23 @end
24 
25 @implementation Egg
26 -(void) draw
27 {
28     NSLog(@"drawing an egg at (%d %d %d %d) in %@",
29           bounds.x,
30           bounds.y,
31           bounds.height,
32           bounds.width,
33           colorName(fillColor));
34 }
35 @end

  通過用繼承方法的修改,代碼冗余問題明顯感覺好了很多。Main() 主函數則完全不用修改,就可以運行,運行結果和之前的一樣:

  在上面的例子中,我們在子類中重新實現了draw的方法,這個過程叫重寫方法。執行的時候,如果子類中有重新定義父類中的方法,那么就會先去執行子類方法,父類中的同名方法則會別忽略。如果子類方法找不到,再去執行父類中定義的方法。

  在OC中,也提供了既可以重寫方法實現,又可以調用父類自身實現的方法。為了調用繼承的方法在父類中出現,需要使用super作為方法調用的目標。當我們向super發送信息的時候,實際上是請求OC向該類的父類發送消息。下面就修改一個使用super關鍵字的例子:

 1 @implementation Circle
 2 -(void) setFillColor:(ShapeColor) c
 3 {
 4     if(c == kRedColor)
 5     {
 6         c = kGreenColor;
 7     }
 8     [super setFillColor: c];
 9 }
10 -(void) draw
11 {
12     NSLog(@"drawing a circle at (%d %d %d %d) in %@",
13           bounds.x,
14           bounds.y,
15           bounds.height,
16           bounds.width,
17           colorName(fillColor));
18 }
19 @end

  我修改了下Circle類的實現方法,對setFillColor方法進行了重新。假如調用的顏色是紅色,則返回的是綠色。在函數的結尾處,使用super關鍵字,通知父類,將新的顏色存儲在fillColor變量中。

  好了,今天對繼承的介紹就先在這告一段落吧。晚安,各位!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM