OC的多態(tài)(運(yùn)行時)轉(zhuǎn)

在介紹多態(tài)之前彻桃,我們來回顧下面向?qū)ο蟮娜齻€特性坛善,封裝、繼承邻眷、多態(tài)

封裝:就是對類中的一些方法眠屎、字段進(jìn)行保護(hù),不被外界訪問肆饶,有一種權(quán)限控制功能改衩,例如OC中有@public、@protected驯镊、@private葫督、@package,默認(rèn)使用@private

繼承:為了代碼的重用,子類可以繼承父類的方法和變量

多態(tài):多態(tài)是指同一操作作用于不同的對象板惑,可以有不同的解釋橄镜,產(chǎn)生不同的執(zhí)行結(jié)果。它是面向?qū)ο蟪绦蛟O(shè)計(OOP)的一個重要特征冯乘,動態(tài)類型能使程序直到執(zhí)行時才確定對象的所屬類洽胶,其具體引用的對象在運(yùn)行時才能確定。動態(tài)綁定能使程序直到運(yùn)行時才確定調(diào)用對象的實際方法裆馒。

C++中的多態(tài)性具體體現(xiàn)在運(yùn)行和編譯兩個方面姊氓,編譯時多態(tài)是靜態(tài)多態(tài)(重載丐怯、模版),在編譯時就可以確定對象使用的形式他膳,運(yùn)行時多態(tài)是動態(tài)多態(tài)(虛函數(shù)响逢,抽象類,覆蓋)棕孙。

C++使用虛函數(shù)(虛函數(shù)表)來實現(xiàn)動態(tài)綁定舔亭,當(dāng)基類對象的指針(或引用)指向派生類的對象時候,實際調(diào)用的是派生類相應(yīng)的函數(shù)蟀俊。

Objective-c 是動態(tài)語言钦铺,所以它具有動態(tài)類型和動態(tài)綁定的特性。Objective-c系統(tǒng)總是跟蹤對象所屬的類肢预。對于類型的判斷和方法的確定都是在運(yùn)行時進(jìn)行矛洞。那Objective-c是怎么樣實現(xiàn)多態(tài)特性的呢?

二 Objective-c多態(tài)

首先看下面代碼

draw.h文件

@interfaceDraw :NSObject

@property(nonatomic,strong)NSString*name;

- (void) Print;

- (void) draw;

@end

draw.m文件

#import"Draw.h"

@implementationDraw

@synthesizename;

- (id) init

{

if(self= [superinit])

{

self.name=@"Draw Demo";

}

returnself;

}

- (void) draw

{

NSLog(@"Draw::draw.......");

}

- (void) Print

{

NSLog(@"i am? %@.",self.name);

}

@end

cricle.h文件

#import"Draw.h"

@interfaceCircle :Draw

@end

circle.m文件

#import"Circle.h"

@implementationCircle

- (void) draw

{

NSLog(@"%@:draw circle",self.name);

}

@end

Retangle.h文件

#import"Draw.h"

@interfaceRetangle :Draw

@end

Retangle.m文件

#import"Retangle.h"

@implementationRetangle

- (void) draw

{

[superdraw];//通過super關(guān)鍵字可以調(diào)用基類的draw函數(shù)

NSLog(@"%@:draw retangle",self.name);

}

@end

我們定義了一個Draw基類烫映,里面有一個數(shù)據(jù)成員name,和兩個函數(shù)成員draw和Print,Circle和Retangle是從Draw派生的兩個類沼本,他們重寫了基類Draw的draw方法。

代碼使用

Draw* base = [[Circlealloc]init];

[basedraw];//draw circle

NSLog(@"address:%@",base);

base = [[Retanglealloc]init];

[basedraw];//draw retangle

NSLog(@"address:%@",base);

[basePrint];

輸出結(jié)果

2014-04-09 15:34:41.648 duotaidemo[7718:303] Draw Demo:draw circle

2014-04-09 15:34:41.673 duotaidemo[7718:303] address:

2014-04-09 15:34:41.674 duotaidemo[7718:303] Draw::draw.......

2014-04-09 15:34:41.674 duotaidemo[7718:303] Draw Demo:draw retangle

2014-04-09 15:34:41.675 duotaidemo[7718:303] address:

2014-04-09 15:34:41.676 duotaidemo[7718:303] i am? Draw Demo.

使用基類的指針分別指向創(chuàng)建的兩個派生類對象,然后分別調(diào)用各自的draw函數(shù)锭沟,通過輸出結(jié)果可以發(fā)現(xiàn)他們調(diào)用的是各自的draw方法抽兆。由于Retangele沒有重寫基類的Print函數(shù),所有使用[base Print]調(diào)用的是基類的方法族淮。同時通過address的輸出發(fā)現(xiàn)base指向了兩個不同的對象辫红。

小結(jié):

1.與C++ 的多態(tài)相比,在Objective-c中是沒有virtual關(guān)鍵字的祝辣,默認(rèn)情況下只要子類重寫了父類的方法就實現(xiàn)了覆蓋(這一點和java類似)贴妻,在Objective-c中同一類中的函數(shù)是不能被重載的。

2.在Objective-c中蝙斜,通過super關(guān)鍵字可以調(diào)用基類的函數(shù)名惩,這個在C++中是沒有的,在C++中可通過作用域運(yùn)算符訪問基類成員孕荠。

除了上面的調(diào)用方式外绢片,我們也可以這樣:

idbase = [[Circlealloc]init];

[basedraw];//draw circle

NSLog(@"address:%@",base);

base = [[Retanglealloc]init];

[basedraw];//draw retangle

NSLog(@"address:%@",base);

[basePrint];

其輸出結(jié)果和上面是一樣的

既然Objective-c中沒有像C++一樣的虛函數(shù)表,那它的多態(tài)是怎么實現(xiàn)的岛琼?它的類型系統(tǒng)是怎么樣構(gòu)建起來的呢底循?繼續(xù)往下看吧!

三 ?類對象

雖然Objective-c沒有虛函數(shù)表槐瑞,但是它有一個根類NSObject,下面讓我們探究一下這個根類是個什么東東熙涤。

objc.h文件中關(guān)于NSObject的定義

@interfaceNSObject

{

Class isaOBJC_ISA_AVAILABILITY;

}

typedefstructobjc_class*Class;

typedefstructobjc_object {

Class isa;

} *id;

typedefstructobjc_selector*SEL;

typedefid(*IMP)(id,SEL, ...);

詳見:http://opensource.apple.com/source/objc4/objc4-493.9/runtime/objc.h

通過上面的定義我們可以知道以下事實:

1.Class isa 是NSObject類的第一個數(shù)據(jù)成員。

2.Class 是一個指針,它指向一個objc_class的結(jié)構(gòu)體祠挫。

3.id 類型是一個指針那槽,它指向一個objc_object的結(jié)構(gòu)體,該結(jié)構(gòu)體只有一個成員即Class isa;

4.id 類型是一個指針等舔,它指向一個存有objc_class的結(jié)構(gòu)對象的指針的指針骚灸。

3.1 isa介紹

以下是蘋果官方文檔對isa的介紹說明:

Every object is connected to the run-time system through its isa instance variable, inherited from the NSObject class. isa identifies the object's class; it points to a structure that's compiled from the class definition. Through isa, an object can find whatever information it needs at run timesuch as its place in the inheritance hierarchy, the size and structure of its instance variables, and the location of the method implementations it can perform in response to messages.

實例變量是通過isa成員鏈接到運(yùn)行時系統(tǒng)環(huán)境中的,任意NSObject的子類都會繼承NSObject的isa成員,而且當(dāng)NSObject的子類實例化對象時,isa實例變量永遠(yuǎn)是對象的第一個實例變量慌植。isa指向該對象的類對象,它是實例和類對象連接的橋梁甚牲。

實例變量和類對象的關(guān)聯(lián),如下圖所示:

下面是類對象(objc_class)的結(jié)構(gòu)體

structobjc_class {

Class isa;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* metaclass */? ? ? ? ? ? ? ? Class super_class? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 父類的地址 */constchar*name? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 類名稱? */longversion? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 版本? ? */longinfo? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 類信息? */longinstance_size? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 實例大小? */structobjc_ivar_list *ivars? ? ? ? ? ? ? ? ? ? /*? 實例參數(shù)列表*/structobjc_method_list **methodLists/*? 方法列表? */structobjc_cache *cache? ? ? ? ? ? ? ? ? ? ? /*? 方法緩存? */structobjc_protocol_list *protocols/*? protocol鏈表*/

} ;

在Objective-C中類也是一種對象,而且在程序運(yùn)行時一直存在蝶柿。類對象是一個根據(jù)類定義生成的一個結(jié)構(gòu)體,里面存儲了類的基本信息, 如:類的大小,類的名稱,類的版本以及消息與函數(shù)的映射表等信息丈钙。類對象所保存的信息在程序編譯時確定,在程序啟動 時加載到內(nèi)存中。

3.2 id介紹

由上面的定義我們知道交汤,id類型是一個指向類對象的指針的指針雏赦。在Objective-c中,id類型是一種通用的指針類型芙扎,id類型可以用來指向?qū)儆谌魏晤惖膶ο?只要該對象是屬于NSObject即成體系)星岗。

id類型的使用如下圖所示:

在使用id類型的時候要注意:

1. id類型本事是一個指針類型,在使用時就不用加*號了戒洼,例如上面的例子idbase = [[Circlealloc]init];

2.id類型是通用指針類型俏橘,弱類型,編譯時不進(jìn)行類型檢查

Objective-C可以將對象分為id類型和靜態(tài)類型施逾,如果不涉及到多態(tài)敷矫,盡量使用靜態(tài)類型例获。

在上的例子中我們使用了兩種方式來調(diào)用派生類函數(shù)汉额,第一種使用的即使靜態(tài)類型,第二種使用的是id動態(tài)類型榨汤。在寫代碼時候蠕搜,盡量使用靜態(tài)類型,靜態(tài)類型可更好的在編譯階段而不是運(yùn)行階段指出錯誤收壕,同時能夠提高程序的可讀性妓灌。

四 小結(jié)

實例變量中isa成員用于保持其類對象在內(nèi)存的地址,類對象對于所有實例來說在內(nèi)存中只有一份副本蜜宪,任何一個實例都可以通過 isa成員虫埂,訪問類對象所保持的類的信息,isa成員可以通過類對象獲得當(dāng)前實例可以訪問的消息列表圃验,以及消息對應(yīng)的函數(shù)地址掉伏。

Objecive-c使用類對象的形式來實現(xiàn)運(yùn)行多態(tài),每個對象都保存其類對象的地址,類對象中保存了類的基本信息斧散。類對象是進(jìn)行動態(tài)創(chuàng)建(反射)供常,動態(tài)識別,消息傳遞等機(jī)制的基礎(chǔ)鸡捐。

那么上面的程序中栈暇,函數(shù)的調(diào)用過程時怎么樣利用類對象的呢?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末箍镜,一起剝皮案震驚了整個濱河市源祈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鹿寨,老刑警劉巖新博,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脚草,居然都是意外死亡赫悄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門馏慨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埂淮,“玉大人,你說我怎么就攤上這事写隶【笞玻” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵慕趴,是天一觀的道長痪蝇。 經(jīng)常有香客問我,道長冕房,這世上最難降的妖魔是什么躏啰? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮耙册,結(jié)果婚禮上给僵,老公的妹妹穿的比我還像新娘。我一直安慰自己详拙,他們只是感情好帝际,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著饶辙,像睡著了一般蹲诀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弃揽,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天脯爪,我揣著相機(jī)與錄音珊佣,去河邊找鬼。 笑死披粟,一個胖子當(dāng)著我的面吹牛咒锻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播守屉,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼惑艇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拇泛?” 一聲冷哼從身側(cè)響起滨巴,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俺叭,沒想到半個月后恭取,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡熄守,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年蜈垮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裕照。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡攒发,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晋南,到底是詐尸還是另有隱情惠猿,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布负间,位于F島的核電站偶妖,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏政溃。R本人自食惡果不足惜趾访,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玩祟。 院中可真熱鬧腹缩,春花似錦屿聋、人聲如沸空扎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽转锈。三九已至,卻和暖如春楚殿,著一層夾襖步出監(jiān)牢的瞬間撮慨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留砌溺,地道東北人影涉。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像规伐,于是被迫代替她去往敵國和親蟹倾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容