如果你還不理解多態(tài)宫患,不妨看看我的

多態(tài)(Objective-C)

一刊懈、多態(tài)的概念

場景1:

老師:【操著四川口音】,童鞋門娃闲,今天虚汛,老師給你們講講神馬是多態(tài)。
小明:啥皇帮?墮胎卷哩?【淫笑】。
老師:小明属拾,你出去将谊。

多態(tài):在程序員的世界,多態(tài)就是相同的方法渐白,不同的實現(xiàn)尊浓。

場景2:

老師:請同學們用“欣欣向榮”來造句。
小紅:祖國的事業(yè)欣欣向榮纯衍。
小明:欣欣向榮榮表白栋齿,遭到拒絕。
老師:小明襟诸,你出去褒颈。

如果說用欣欣向榮造句是一條消息,小紅和小明是兩個對象励堡,我們可以看到谷丸,不同的對象,響應相同的消息应结,得到的是完全不同的結果刨疼。這種不同對象響應相同消息的能力就是【多態(tài)】

把上面的場景翻譯成程序員語

定義一個Boy類

@interface Boy : NSObject

- (void)makeStatementsWithWord:(NSString*)word;


@end
@implementation Boy

- (void)makeStatementsWithWord:(NSString*)word {
    NSLog(@"%@榮表白鹅龄,遭到了拒絕",word);
}
@end

定義一個Girl類

@interface Girl : NSObject

- (void)makeStatementsWithWord:(NSString*)word;

@end
@implementation Girl

- (void)makeStatementsWithWord:(NSString*)word {
    NSLog(@"祖國的建設事業(yè) %@",word);
}

@end

兩個類都帶一個方法名為- (void)makeStatementsWithWord:(NSString*)word;的實例方法揩慕。這個方法的參數(shù)表示用來造句的詞。

main函數(shù)如下

    Boy* xiaoMing = [[Boy alloc] init];
    [xiaoMing makeStatementsWithWord:@"欣欣向榮"];

    Girl* xiaoHong = [[Girl alloc] init];
    [xiaoHong makeStatementsWithWord:@"欣欣向榮"];

打印結果如下:

20XX-XX-XX 11:04:31.990 test[2751:393671] 欣欣向榮榮表白扮休,遭到了拒絕
20XX-XX-XX 11:04:31.991 test[2751:393671] 祖國的建設事業(yè) 欣欣向榮

如果你已經(jīng)能舉出一些類似的例子迎卤,那說明你已經(jīng)對多態(tài)有一個初步的認識了。

下面我要講一個故事玷坠。通過這個故事蜗搔,你會加深對多態(tài)的理解劲藐。

二、動態(tài)綁定和id類型

大歡和大鵬是我的兩位得力助手樟凄,大歡是講師聘芜,人稱刀疤歡,他的“刀疤”是被樹枝刮傷的缝龄。大鵬是程序員汰现,人稱傻鵬,顯然我們不必再去討論他的智商問題叔壤。

故事就發(fā)生在他們倆身上瞎饲。
現(xiàn)在我需要他們倆去幫我給一位新來的女同事做一個面試,然后給我一個反饋結果炼绘。我給這個幫我做面試的人起了一個代號企软,叫simple(一個頭腦簡單的面試官)。顯然我公司對待面試是很重視的饭望。

然后,我先讓大歡上場形庭,所以這個時候simple就是大歡铅辞。
然后大歡經(jīng)過2個小時的面試,給出我一個這樣簡單的反饋:

1.溝通能力很強
2.編碼能力很強
3.項目經(jīng)驗豐富
4.薪資要求很低
非常適合我們公司

顯然對于我這樣一個嚴格要求能力的人萨醒,這樣的答復是不夠的斟珊。我還批評了大歡做事太粗糙。

然后我決定讓大鵬再去幫我做一個面試富纸。這個時候simple就是大鵬囤踩。大鵬經(jīng)過5分鐘以后也回來給了我一個反饋。

1.很漂亮
2.沒有男朋友

最后經(jīng)過慎重的考慮晓褪,我決定錄用她了堵漱。

【拍磚】哎哎,課還沒講完呢你們都干嘛去盎练隆勤庐?

好我們正經(jīng)一點,如果simple能表示大歡又能表示大鵬好港,那么它到底是個什么類型呢愉镰?是講師類型還是程序員類型? 顯然用哪一種都不合適钧汹。所以丈探,OC給我們提供一種更加寬泛的類型,即id類型拔莱。
id類型可以表示任意的對象類型碗降。注意隘竭,一定是對象類型,非對象類型是不可以的遗锣。而且后面沒有星號*货裹。

例如:
Teacher* daPeng = [Teahcer new];
id simple = daPeng; // 正確
id value = 5; // 錯誤 不能表示非對象類型
id* value1 = daPeng; // 錯誤 id后面沒有星號

我們把上面的例子,使用代碼表示如下:

定義Teacher類

@interface Teacher : NSObject

- (void)haveInterview;

@end
@implementation Teacher

- (void)haveInterview {
    NSLog(@"1.很漂亮");
    NSLog(@"2.沒有男朋友");
}
@end

定義Coder類

@interface Coder : NSObject

- (void)haveInterview;

@end
@implementation Coder

- (void)haveInterview {
    NSLog(@"1.溝通能力很強");
    NSLog(@"2.編碼能力很強");
    NSLog(@"3.項目經(jīng)驗豐富");
    NSLog(@"4.薪資要求很低");
    NSLog(@"非常適合我們公司");
}
@end

main函數(shù)如下:

    // 大歡大鵬上場
    Coder* daHuan = [Coder new];
    Teacher* daPeng = [Teacher new];

    // 大歡成為面試官simple
    id simple = daHuan;
    [simple haveInterview];

    // 大鵬成為面試官simple
    simple = daPeng;
    [simple haveInterview];

打印結果:

1.溝通能力很強
2.編碼能力很強
3.項目經(jīng)驗豐富
4.薪資要求很低
非常適合我們公司
1.很漂亮
2.沒有男朋友

細心的同學可能已經(jīng)注意到精偿,我們兩次向simple發(fā)送haveInterview消息弧圆,系統(tǒng)是如何區(qū)分當前應該執(zhí)行哪一種haveInterview消息呢?

動態(tài)綁定:事實上笔咽,OC的系統(tǒng)總是跟蹤當前對象所屬的類搔预,然后在運行時確定需要調(diào)用的方法,而不是在編譯時叶组。

因此拯田,當simple接收到haeInterview消息時,系統(tǒng)首先去追蹤當前simple表示的是屬于哪個類的對象甩十,進而確定當前該執(zhí)行哪個類的方法船庇。
所以便有了當大歡作為simple得到的是

1.溝通能力很強
2.編碼能力很強
3.項目經(jīng)驗豐富
4.薪資要求很低
非常適合我們公司

而當大鵬作為simple的時候,得到的是

1.很漂亮
2.沒有男朋友

三侣监、編譯時和運行時檢查

在使用id類型表示的對象類型鸭轮,在編譯時是并沒有確定該對象類型的,事實上這個時候也無法確定類型橄霉。就像來參加面試那個妹子窃爷,她并不認識大歡和大鵬,她只知道與他對話的是一個面試官(前面我們使用simple代號來表示)姓蜂。直到開始面試時按厘,才確定當前面試官simple到底是大鵬還是大歡。

也就是說钱慢,id表示的對象類型是在程序運行時檢查出來的逮京。

例如大歡喜歡在討論技術的時候,會喜歡先給你一個不屑的眼神然后在給你耐心講解這個知識點更深入的一層含義束莫,我們把他的這種行為稱為zhuangBiTeach造虏,大鵬喜歡在課下給他的學生解決一些技術難題,我們把他的這種行為稱為debugTeach麦箍。

這樣我們需要把上面的兩個類做如下修改:

1.教師類

@interface Teacher : NSObject

- (void)haveInterview;
- (void)debugTeach;

@end
@implementation Teacher

- (void)haveInterview {
    NSLog(@"1.很漂亮");
    NSLog(@"2.沒有男朋友");
}

- (void)debugTeach {
    NSLog(@"大鵬幫你定位了bug并分析了原因");
    NSLog(@"然后梳理了一下思路漓藕,分分鐘完美解決了bug");
}
@end

2.程序員類

@interface Coder : NSObject

- (void)haveInterview;
- (void)zhuangbiTeach;

@end
@implementation Coder

- (void)haveInterview {
    NSLog(@"1.溝通能力很強");
    NSLog(@"2.編碼能力很強");
    NSLog(@"3.項目經(jīng)驗豐富");
    NSLog(@"4.薪資要求很低");
    NSLog(@"非常適合我們公司");
}

- (void)zhuangbiTeach {
    NSLog(@"大歡向你拋出了一個白眼");
    NSLog(@"哎哎,你們聊的這個層面太淺挟裂,讓哥來給你迷途指引一下方向");

}
@end

在主函數(shù)中享钞,做如下處理

    // 大鵬上場
    Teacher* daPeng = [Teacher new];

    // 大鵬成為面試官simple
    id simple = daPeng;

    // 此處編譯時沒錯,運行時報錯
    [simple zhuangbiTeach];

如上,[simple zhuangbiTeach]; 這行代碼會報錯栗竖。報錯結果如下

-[Teacher zhuangbiTeach]: unrecognized selector sent to instance 0x1001057a0

也就是說Teacher類實例并不能響應zhuangbiTeach方法暑脆。

在程序編譯階段,因為系統(tǒng)無法確定simple表示的對象類型狐肢,系統(tǒng)只能確定zhuangbiTeach是一個有效的方法添吗。所以沒有報錯。而zhuangbiTeach是大歡的技能份名,聲明在Coder類中碟联,當程序運行時,追蹤simple所表示的對象是一個Teacher對象僵腺,而Teacher類并沒有實現(xiàn)zhuangbiTeach方法鲤孵,所以程序在運行時報錯了。

id數(shù)據(jù)類型與靜態(tài)類型

初學的小伙伴經(jīng)常會問我辰如,智哥普监,既然id類型可以表示任意類型的對象,那以后我就都用id類型來表示對象啦琉兜。當然凯正,新手總是對新技術充滿好奇,這個我非常理解豌蟋。所以這個時候廊散,我總會耐心的做如下解釋,你咋不上天呢夺饲?

我不得不給大家講一點哲學。需知萬事皆有度施符,物極必反啊往声。沒有什么是絕對的好,也沒有什么是絕對的不好戳吝。好與不好是要分場景的浩销。一個妹子跑到你面前說你好帥,然后把從小朋友手里搶的棒棒糖送給你听哭,你能說她不好嗎慢洋?

為了理解為什么不能一直用id類型,我們先理解兩種類型陆盘,靜態(tài)類型和動態(tài)類型普筹。靜態(tài)類型就是我們使用類名字來聲明的對象指針,動態(tài)類型就是id類型隘马。比如我們定義大鵬可以使用如下兩種方式來表示他

1. id daPeng = [[Teacher alloc] init]; // 動態(tài)類型
2. Teacher* daPeng = [[Teacher alloc] init]; // 靜態(tài)類型

我想我已經(jīng)表述清楚什么是動態(tài)類型什么是靜態(tài)類型了太防。

使用靜態(tài)類型時,編譯器可以盡可能的確保變量的用法在程序中始終保持一致酸员。它可以在編譯階段檢查來確定這個對象要調(diào)用的方法是否可以成功響應蜒车。否則將直接報錯讳嘱。也就是說,使用靜態(tài)類型酿愧,可以更好的在編譯階段而不是運行階段查錯沥潭。

另外id daPeng 和 Teacher* daPeng兩種方式中,顯然使用靜態(tài)類型的可讀性更高嬉挡。所以钝鸽,對于程序的自說明性也是有非常重大的意義的。

注意:由于id不是一個具體的類型棘伴,系統(tǒng)在編譯階段無法確定寞埠,所以id也不能使用點運算符訪問屬性。

動態(tài)類型的使用

動態(tài)類型的使用焊夸,得益于多態(tài)是被支持的仁连。一般體現(xiàn)在多態(tài)類型作參數(shù)和做返回值兩個方面。

再來一個小故事阱穗。大歡一直為自己的發(fā)型感到驕傲饭冬。但最近他想換一個新發(fā)型。所以他決定去找一個給力的發(fā)型師幫他設計一款新發(fā)型揪阶。故事就此展開昌抠。

先設計一個發(fā)型師Designer類

@interface Designer : NSObject

- (void)showHairStyle;

@end
@implementation Designer

- (void)showHairStyle {
    NSLog(@"不是每一位發(fā)型師都會設計發(fā)型");
}

@end

再設計一個大歡所屬的Coder類,大歡需要有一個方法鲁僚,就是尋找一位發(fā)型師炊苫,由于發(fā)型師可以是很多不同風格的發(fā)型師,所以使用id類型來表示不同風格的發(fā)型師

@interface Coder : NSObject

- (void)designHairStyle:(id)designer;

@end
// 為保證showHairStyle是可以被系統(tǒng)識別的冰沙,所以導入Designer.h
#import "Designer.h"
@implementation Coder

- (void)designHairStyle:(id)designer {

    [designer showHairStyle];
}

@end

Coder類侨艾,有一個designHairStyle方法,參數(shù)是一個id類型拓挥。表示需要一個設計師來設計發(fā)型唠梨。

那么,只要有一個對象侥啤,它繼承自Designer類当叭,就可以成為設計師,來幫助大歡設計發(fā)型盖灸。

所以蚁鳖,我們設計兩個Designer的子類

1.男發(fā)型師
#import "Designer.h"

@interface ManDesigner : Designer

@end
@implementation ManDesigner

- (void)showHairStyle {
    NSLog(@"一款光滑的光頭發(fā)型");
}
@end

2.女發(fā)型師

#import "Designer.h"

@interface WomanDesigner : Designer

@end
@implementation WomanDesigner

- (void)showHairStyle {
    NSLog(@"一款飄逸的長發(fā)及腰");
}
@end

main函數(shù)如下:
先導入兩個頭文件
#import "ManDesigner.h"
#import "WomanDesigner.h"

代碼如下:

    Coder* daHuan = [[Coder alloc] init];

    ManDesigner* tom = [[ManDesigner alloc] init];
    WomanDesigner* lucy = [[WomanDesigner alloc] init];

    [daHuan designHairStyle:tom];
    [daHuan designHairStyle:lucy];

打印結果:

一款光滑的光頭發(fā)型
一款飄逸的長發(fā)及腰

如果大歡對設計的發(fā)型不滿意,可以再找一位發(fā)型師赁炎,只要這位發(fā)型師也實現(xiàn)了showHairStyle方法即可才睹。

所以,多態(tài)的存在,讓我們的程序可以設計的更加靈活琅攘。然而垮庐,在使用動態(tài)類型的時候,也會存在很多潛在風險坞琴。比如哨查,我們使用id類型來表示一個設計師,如果這個設計師并不會設計發(fā)型(沒有實現(xiàn)showHairStyle方法)剧辐,當大歡調(diào)designHairStyle方法時寒亥,用程序就會報錯。所以下節(jié)課我們來學習荧关,如何規(guī)避這些風險溉奕。

如有疏漏,敬請指正忍啤,下次再見加勤!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市同波,隨后出現(xiàn)的幾起案子鳄梅,更是在濱河造成了極大的恐慌,老刑警劉巖未檩,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戴尸,死亡現(xiàn)場離奇詭異,居然都是意外死亡冤狡,警方通過查閱死者的電腦和手機孙蒙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悲雳,“玉大人挎峦,你說我怎么就攤上這事×保” “怎么了浑测?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵翅阵,是天一觀的道長歪玲。 經(jīng)常有香客問我,道長掷匠,這世上最難降的妖魔是什么滥崩? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮讹语,結果婚禮上钙皮,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好短条,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布导匣。 她就那樣靜靜地躺著,像睡著了一般茸时。 火紅的嫁衣襯著肌膚如雪贡定。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天可都,我揣著相機與錄音缓待,去河邊找鬼。 笑死渠牲,一個胖子當著我的面吹牛旋炒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播签杈,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼瘫镇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芹壕?” 一聲冷哼從身側響起汇四,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎踢涌,沒想到半個月后通孽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡睁壁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年背苦,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潘明。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡行剂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钳降,到底是詐尸還是另有隱情厚宰,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布遂填,位于F島的核電站铲觉,受9級特大地震影響,放射性物質發(fā)生泄漏吓坚。R本人自食惡果不足惜撵幽,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望礁击。 院中可真熱鬧盐杂,春花似錦逗载、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至强衡,卻和暖如春捏膨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背食侮。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工号涯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锯七。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓链快,卻偏偏與公主長得像,于是被迫代替她去往敵國和親眉尸。 傳聞我的和親對象是個殘疾皇子域蜗,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

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

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法噪猾,內(nèi)部類的語法霉祸,繼承相關的語法,異常的語法袱蜡,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理丝蹭,服務發(fā)現(xiàn),斷路器坪蚁,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • 轉自:http://blog.csdn.net/jackfrued/article/details/4492194...
    王帥199207閱讀 8,500評論 3 93
  • 從三月份找實習到現(xiàn)在奔穿,面了一些公司,掛了不少敏晤,但最終還是拿到小米贱田、百度、阿里嘴脾、京東男摧、新浪、CVTE译打、樂視家的研發(fā)崗...
    時芥藍閱讀 42,194評論 11 349
  • 關于Qt開發(fā)耗拓,數(shù)據(jù)的臨時存儲及調(diào)用,可以使用C++編成之MVC設計模式扶平。Model:模型數(shù)據(jù) 定義View:前端視...
    YBshone閱讀 9,602評論 0 0