Objective-C中的繼承和多態


   面向對象編程之所以成為主流的編程思想和他的繼承和多態是分不開的,只要是面向對象語言都支持繼承和多態,當然不同的OOP語言之間都有其特點。OC中和Java類似,不支持多重繼承,但OOP語言C++就支持多繼承,為什么OC不支持多繼承稍后將會提到。

   說到繼承呢,想到了一本書上是引用《大話西游》里的一句話來描述繼承的。“人是人他媽生的,妖是妖他媽生的!”,想必里面的唐三藏也學過OOP編程,也許他們師徒四人去西天取什么算法導論呢,漫談OOP編程啦,數據結構啦等這類的書去啦。人和妖都屬於動物類,但各自有各自的特點,各自有各自的不同,動物就是父類,而人和妖就是子類。繼承的目的是為了減少代碼的冗余,還是DRY原則(don`t repeat yourself)。

        在Objective-C中super是指向直接父類的指針,而self是指向本身的指針,self就相當於java中的this指針。在OC中寫類時可以在@implementation中定義哪些在@interface中無相應聲明的方法,但這個方法是私有的,僅在類的實現中使用。


        在Objectiv-C中幾乎所有的類都是繼承自NSObject類,NSObject類中存在大量功能強大的方法。下面對NSObject類中的各種方法進行試驗和介紹:

        1. +(void) load;  類加載到運行環境時調用該方法

                測試:在子類中重寫load方法來進行測試, 當重寫完load方法,在mian方法中不需要任何實例化任何對象

                            當類被加載時load就會別調用.load是類方法,可以直接被類調用

1
2
3
4
5
//重寫NSObject中的load方法
+( void ) load
{
     NSLog(@ "ObjectTest中的load方法被調用啦!!" );
}

       運行結果:

1
2014-07-30 08:58:31.704 HelloOC[550:303] ObjectTest中的load方法被調用啦!!

  

        2. +(void) initialize;  在類第一次使用該類時調用該方法,第二次就不調用了

                測試:重寫initalize方法

1
2
3
4
5
//重寫initialize方法,會在類第一次使用時調用
+( void ) initialize
{
     NSLog(@ "initialize方法被調用了(類第一次被實例化)!" );
}

            運行結果:

1
2
2014-07-30 09:27:53.767 HelloOC[624:303] load方法被調用啦!!
2014-07-30 09:27:53.769 HelloOC[624:303] initialize方法被調用了(類第一次被實例化)!

 

    3. +(id) alloc:  返回一個已經分配好的內存對象;  -(id) init: 對已經分配了內存的實例進行初始化; new同時調用了alloc 和 init

        demo:   Object  *object = [[Object alloc] init];

        可以在子類中把alloc進行重寫,然后觀察運行情況

1
2
3
4
5
6
//重寫alloc方法
+(id) alloc
{
    NSLog(@ "alloc函數被調用啦" );
     return  [super alloc];
}
1
2
3
4
5
6
7
//重寫init
-(id) init
{
     NSLog(@ "init被調用了" );
     self = [super init];
     return  self;
}

        

        測試方法一個用alloc和init實例化類,一個用new實例化類:

1
2
3
4
5
//第一次使用ObjectTest類
ObjectTest *o1 = [[ObjectTest alloc] init];
 
//第一次使用ObjectTest類
ObjectTest *o2 = [ObjectTest  new ];

                運行結果:

1
2
3
4
5
6
2014-07-30 09:59:58.991 HelloOC[689:303] load方法被調用啦!!
2014-07-30 09:59:58.993 HelloOC[689:303] initialize方法被調用了(類第一次被實例化)!
2014-07-30 09:59:58.993 HelloOC[689:303] alloc函數被調用啦
2014-07-30 09:59:58.993 HelloOC[689:303] init被調用了
2014-07-30 09:59:58.994 HelloOC[689:303] alloc函數被調用啦
2014-07-30 09:59:58.994 HelloOC[689:303] init被調用了

     4.-(void)dealloc 釋放對象自身所占有的內存;

 

    5. -(Class)class 或者 +(Class)class 返回當前對象的所屬類;  -(Class)superclass 或者 +(Class)superclass返回當前類的父類

1
2
3
4
5
6
7
//返回當前對象所對應的類
NSString *className =(NSString *) [self  class ];
NSLog(@ "%@類的display方法" , className);
 
//返回當前對象所對應的父類
NSString *superClassName = (NSString *) [self superclass];
NSLog(@ "%@類的父類是%@" , className, superClassName);

 

    6、-(BOOL)isKindOfClass : (Class)aClass 判斷某個實例是否屬於某個類或者子類的對象

        事例代碼如下:

1
2
3
4
5
//isKindOfClass的用法
BOOL  b =  [o2 isKindOfClass:[ObjectTest  class ]];
if  (b == YES) {
     NSLog(@ "o2是ObjectTest類的對象" );
}

 

    7.-(BOOL)isMemberOfClass:(Class)aClass;  只能判斷摸個實例是否屬於某個類,不能判斷是否屬於某個父類;

1
2
3
4
5
//isMemberOfClass
BOOL  result = [o2 isMemberOfClass:[NSObject  class ]];
if  (result == NO) {
     NSLog(@ "isMemberOfClass不能判斷是否為NSObject子類的對象" );
}

 

    8.-(NSString *) description; 返回字符串形式對象的描述,方便調試

1
2
3
//description
NSString *descript = [o2 description];
NSLog(@ "%@" , descript);

        輸出結果: <ObjectTest: 0x100206650>

     9.-(NSUInteger) hash; 返回對象的哈希值;

1
2
3
//hash的用法
NSUInteger hash = [o2 hash];
NSLog(@ "%p" , hash);

        輸出結果:2014-07-30 11:40:35.685 HelloOC[1130:303] 0x100107b70

    ​10.-(BOOL) isEqual:(id)object; 比較兩個對象是否相同,默認是使用地址進行比較的,且hash值一定要相同

1
2
3
4
5
6
7
8
9
10
11
//isEqual的用法
NSString *str1 = @ "111" ;
NSString *str2 = str1;
if  ([str2 isEqual:str1] == YES)
{
     NSLog(@ "str2 == str1" );
}
else
{
     NSLog(@ "str2 != str1" );
}

 


    ​    ​Objective-C中的繼承

         繼承是is-a的關系,比如貓咪是一個動物,那么動物是父類,而貓咪是動物的子類。子類具有父類的屬性和 行為,以及自身的屬性和行為,也就是說“父類更一般,子類更具體”。用一個富二代的類來說明一下類的繼承。

 1.先定義一個富人的類

        代碼說明:

                1.聲明訪問權限為@protected的三個屬性,分別為三個屬性用@property加上getter和setter方法

                2.並為該類創建便利初始化方法和便利構造器

                3.為富人類定義一個刷卡方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//
//  Richer.h
//  HelloOC
//
//  Created by ludashi on 14-7-29.
//  Copyright (c) 2014年 ludashi. All rights reserved.
//
 
#import <Foundation/Foundation.h>
 
@interface Richer : NSObject
{
     @ protected
     NSString *name;
     int  age;
     NSString *gender;
 
}
 
//定義富人的姓名,年齡,性別,並為其提供getter和setter方法
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic)  int  age;
@property (copy, nonatomic) NSString *gender;
 
//定義便利初始化方法
-(id) initWithName : (NSString *)vName
             AndAge : ( int )vAge
          AndGender : (NSString *)vGender;
 
//定義便利構造器
+(id) richerWithName : (NSString *)vName
               AndAge : ( int )vAge
            AndGender : (NSString *)vGender;
 
//定義刷卡方法
-( void ) poss;
 
@end

    

    2.為富人類編寫實現代碼

            代碼說明:

                1.用@synthesize實現getter和setter方法

                2.實現便利初始化方法,用[ super init ]初始化富人類的直接父類,也就是NSObject

                3.使用便利構造器返回實例化並初始化后的對象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#import "Richer.h"
@implementation Richer
//實現getter和setter方法
@synthesize name, age, gender;
//實現便利初始化函數
-(id) initWithName : (NSString *)vName
             AndAge : ( int )vAge
          AndGender : (NSString *)vGender
{
     if  (self = [super init])
     {
         self->name = vName;
         self->age = vAge;
         self->gender = vGender;
     }
     return  self;
}
//實現便利構造器
+(id) richerWithName:(NSString *)vName
               AndAge:( int )vAge
            AndGender:(NSString *)vGender
{
     Richer *richer = [[Richer alloc] initWithName:vName
                                            AndAge:vAge
                                         AndGender:vGender];
     return  richer;
}
//實現刷卡方法
-( void ) poss
{
     NSLog(@ "%@有錢你就刷吧" , name);
}@end

 

    3.編寫富二代的類,富二代和富人有許多相似的屬性和方法所以富二代繼承於富人類,並添加相應的屬性和方法,把需要重寫的方法進行重寫。

            代碼說明:

                1.為富二代類添加新的愛好屬性

                2.為富二代添加新的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import "Richer.h"
 
@interface Richer2nd : Richer
//Richer2nd繼承啦Richer所有的方法
 
//為富二代添加新的屬性
@property (copy, nonatomic) NSString *hobby;
 
 
//便利初始化函數
-(id) initWithName : (NSString *) vName
             AndAge : ( int )vAge
          AndGender : (NSString *) vGender
           AndHobby : (NSString *)vHobby;
//為Richer2nd編寫便利構造器
+(id)richer2ndWithName : (NSString *) vName
                 AndAge : ( int )vAge
              AndGender : (NSString *) vGender
               AndHobby : (NSString *)vHobby;
 
//添加hobby方法
-( void ) myHobby;
 
@end

 

 

    4.各種方法的實現

            代碼說明:

                    1.在編寫便利初始化方法時利用super來調用父類的便利初始化方法來把繼承到的父類的方法進行初始化

                    2.用self給新添加的屬性進行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#import "Richer2nd.h"
 
@implementation Richer2nd
//實現屬性的getter和setter方法
@synthesize hobby;
 
//編寫便利初始化函數,復用父類的便利初始化方法
-(id)initWithName:(NSString *)vName
            AndAge:( int )vAge
         AndGender:(NSString *)vGender
          AndHobby:(NSString *)vHobby
{
     if  (self = [super initWithName:vName AndAge:vAge AndGender:vGender]) {
         self->hobby = vHobby;
     }
     return  self;
}
 
//編寫便利構造函數
+(id)richer2ndWithName:(NSString *)vName
                 AndAge:( int )vAge
              AndGender:(NSString *)vGender
               AndHobby:(NSString *)vHobby
{
     Richer2nd *richer = [[Richer2nd alloc] initWithName:vName AndAge:vAge AndGender:vGender AndHobby:vHobby];
     return  richer;
 
}
 
//重寫刷卡方法
-( void )poss
{
     [super poss];
     NSLog(@ "我是富二代,我爸有錢,我就刷!" );
}
 
//添加新的方法
-( void ) myHobby
{
     NSLog(@ "我是富二代%@,我超喜歡%@" , name, hobby);
}
 
 
@end

    

 

    5.以下是上面代碼的運行結果

1
2
3
4
2014-07-30 08:38:12.956 HelloOC[483:303] Bill有錢你就刷吧
2014-07-30 08:38:12.957 HelloOC[483:303] BILL`s son有錢你就刷吧
2014-07-30 08:38:12.958 HelloOC[483:303] 我是富二代,我爸有錢,我就刷!
2014-07-30 08:38:12.958 HelloOC[483:303] 我是富二代BILL`s son,我超喜歡飆車

 

 


​Objective-C中的多態

    ​    ​多態簡單的說就是對於不同對象響應同一個方法時做出的不同反應。在 OC中動態類型id是實現多態的一種方式,id是一個獨特的數據類型,可以轉換為任何數據類型,上面的富人和富二代可以這樣定義

 

1
2
3
4
5
6
7
8
9
10
id richer = nil;
 
//測試富人類
richer = [Richer richerWithName:@ "Bill"  AndAge:40 AndGender:@ "Man" ];
[richer poss];
 
//測試富二代的類
richer = [Richer2nd richer2ndWithName:@ "BILL`s son"  AndAge:16 AndGender:@ "男"  AndHobby:@ "飆車" ];
[richer poss];
[richer myHobby];

    ​上面程序的輸出結果和繼承部分的結果是一致的;

    ​多態的另一個例子: Animal是父類,子類有Cat 和 Dog,子分別重寫了父類中的eat方法;實例化對象的時候可以用下面的方法:

1
2
3
4
5
6
7
Animal *animal = nil;
 //實例化貓的對象
animal = [Cat  new ];
[animal eat];
 //實例化狗的對象
animal = [Dog  new ];
[animal eat];

 

面向對象編程中的OCP原則和LSP原則

    ​OCP : Open Closed Principle原則, 對擴展開放,對修改關閉

    ​  LSP :里氏代換原則,任何基類可以出現的地方,子類一定可以出現。


免責聲明!

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



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