繼承的基本概念:ide
現實生活中的繼承:工具
人類是一個基類(也稱作父類),一般狀況下全部人類所共同具有的特性,若有手有腳能吃能喝性能
按照生活常規,咱們繼續給人類來細分的時候,咱們能夠分爲學生類 工人類等,學生類和工人類一樣具有手 腳 吃 喝等特性,而這些特性是全部人類所共有的,那麼就可讓學生或工人類繼承人類,這樣當創建學生類和工人類的時候咱們無需再定義人類中已經有的成員和方法,而只須要描述學生類和工人類所特有的特性便可。學習
學生類和工人類的特性是由在人類原有特性基礎上增長而來的,那麼學生類和工人類就是人類的派生類(也稱作子類)。以此類推,層層遞增, 這種子類得到父類特性的概念就是繼承spa
OC中的繼承關係code
繼承是代碼重用的重要方式之一對象
學生類聲明文件.h:blog
#import <Foundation/Foundation.h> @interface Student : NSObject { // 姓名 NSString * _name; // 年齡 int _age; // 學號 int _studengNO; // 身份 NSString * _identity; } - (void) setName:(NSString *) name; - (NSString *) name; - (void) setAge: (int) age; - (int) age; - (void) setStudentNO: (int) studentNO; - (int) studentNO; - (void) setIdentity: (NSString *) identity; - (NSString *) identity; // 吃 - (void) eat; // 學習 - (void) study; @end
學生類實現文件.m:繼承
#import "Student.h" @implementation Student - (void)setName:(NSString *)name{ _name = name; } - (NSString *)name{ return _name; } - (void)setAge:(int)age{ _age = age; } - (int)age{ return _age; } - (void)setStudentNO:(int)studentNO{ _studengNO = studentNO; } - (int)studentNO{ return _studengNO; } - (void)setIdentity:(NSString *)identity{ _identity = identity; } - (NSString *) identity{ return _identity; } // 吃 - (void)eat{ NSLog(@"吃東西"); } // 學習 - (void)study{ NSLog(@"學習"); } @end
工人類聲明文件.h:接口
#import <Foundation/Foundation.h> @interface Worker : NSObject { // 姓名 NSString * _name; // 年齡 int _age; // 工號 int _workNO; // 身份 NSString * _identity; } - (void) setName: (NSString *) name; - (NSString *) name; - (void) setAge: (int) age; - (int) age; - (void) setWorkNO: (int) workNO; - (int) workNO; - (void) setIdentity: (NSString *) identity; - (NSString *) identity; // 吃 - (void) eat; // 學習 - (void) study; // 工做 - (void) work; @end
工人類實現文件:
#import "Worker.h" @implementation Worker - (void)setName:(NSString *)name{ _name = name; } - (NSString *)name{ return _name; } - (void)setAge:(int)age{ _age = age; } - (int)age{ return _age; } - (void)setWorkNO:(int)workNO{ _workNO = workNO; } - (int)workNO{ return _workNO; } - (void)setIdentity:(NSString *)identity{ _identity = identity; } - (NSString *) identity{ return _identity; } // 吃 - (void)eat{ NSLog(@"吃東西"); } // 學習 - (void)study{ NSLog(@"學習"); } // 工做 - (void)work{ NSLog(@"上班了 幹活"); } @end
比較一下上面的代碼 看看有多少是重複的:
聲明文件中重複部分:
屬性:
// 姓名 NSString * _name; // 年齡 int _age; // 身份 NSString * _identity;
行爲:
- (void) setName:(NSString *) name; - (NSString *) name; - (void) setAge: (int) age; - (int) age; - (void) setIdentity: (NSString *) identity; - (NSString *) identity; // 吃 - (void) eat; // 學習 - (void) study;
實現文件中重複部分:
- (void)setName:(NSString *)name{ _name = name; } - (NSString *)name{ return _name; } - (void)setAge:(int)age{ _age = age; } - (int)age{ return _age; } - (void)setIdentity:(NSString *)identity{ _identity = identity; } - (NSString *) identity{ return _identity; } // 吃 - (void)eat{ NSLog(@"吃東西"); } // 學習 - (void)study{ NSLog(@"學習"); }
獲得的結果是:
學生類中就一個學號在工人類中沒有
工人類中就一個工號和一個工做的行爲在學生類中沒有
其他部分都是重複代碼
若是還要添加幾個其餘類: 如學前期的幼兒類 退休後的老人類等等 那麼上面那些重複的代碼還得重複好幾遍 複製粘貼都感受累有木有
如今咱們來添加一個Person類 人類中定義屬性有 姓名 (name) 年齡(age) 身份(identity) 行爲有 吃(eat) 學習(study)
使用繼承關係後再來看看代碼:
Person類聲明文件:
#import <Foundation/Foundation.h> @interface Person : NSObject { // 姓名 NSString * _name; // 年齡 int _age; // 身份 NSString * _identity; } - (void) setName:(NSString *) name; - (NSString *) name; - (void) setAge: (int) age; - (int) age; - (void) setIdentity: (NSString *) identity; - (NSString *) identity; // 吃 - (void) eat; // 學習 - (void) study; @end
Person類實現文件:
#import "Person.h" @implementation Person - (void)setName:(NSString *)name{ _name = name; } - (NSString *)name{ return _name; } - (void)setAge:(int)age{ _age = age; } - (int)age{ return _age; } - (void)setIdentity:(NSString *)identity{ _identity = identity; } - (NSString *) identity{ return _identity; } // 吃 - (void)eat{ NSLog(@"吃東西"); } // 學習 - (void)study{ NSLog(@"學習"); } @end
學生類聲明文件:
#import <Foundation/Foundation.h> #import "Person.h" @interface Student : Person { // 學號 int _studengNO; } - (void) setStudentNO: (int) studentNO; - (int) studentNO; @end
學生類實現文件:
#import "Student.h" @implementation Student - (void)setStudentNO:(int)studentNO{ _studengNO = studentNO; } - (int)studentNO{ return _studengNO; } @end
工人類的聲明文件:
#import <Foundation/Foundation.h> #import "Person.h" @interface Worker : Person { // 工號 int _workNO; } - (void) setWorkNO: (int) workNO; - (int) workNO; // 工做 - (void) work; @end
工人類的實現文件:
#import "Worker.h" @implementation Worker - (void)setWorkNO:(int)workNO{ _workNO = workNO; } - (int)workNO{ return _workNO; } // 工做 - (void)work{ NSLog(@"上班了 幹活"); } @end
好了, 如今再來看看代碼: 咱們的代碼中多了一個Person類的聲明和實現文件 在這個類中聲明定義的就是咱們以前學生類和工人類中重複的那一部分.
"B類繼承A類,那麼B類將擁有A類的全部屬性和方法" 就是說若是 咱們讓學生類和工人類都繼承自Person類 , 那麼就算咱們在學生類中和工做類中都沒有聲明那些姓名 年齡 吃 學習之類的屬性和方法, 這兩個類也能從Person類中獲得這些行爲屬性. 而在學生類中只須要聲明學生類特有的學號屬性, 工人類中只須要聲明工人類特有的工號,工做這種特有的行爲屬性便可, 這樣子在學生類和工人類中得代碼看起來簡潔了不少, 並且之後若是咱們須要再添加什麼嬰兒類 老人類, 也只須要在相關類中添加他們特有的行爲屬性就好了.
在這個例子裏, Person類就是父類 學生類和工人類就是Person類的子類, 須要注意的是OC也是單繼承的, 畢竟咱都只有一個父親是吧, (呃 那個 乾爹不算) , 在父類中定義的全部行爲屬性, 子類都能繼承過去, 而在子類中還能夠添加他特有的行爲屬性, 也就是說我爸有的 我都有, 我有的, 我爸不必定有(例如: 我會打Dota 我爸不會 ).
當咱們發現兩個類中有定義不少重複的行爲屬性的時候, 即可以把這些重複的部分都抽取出來當一個父類; 繼承對代碼的重用性和可擴展性 , 看上面例子體會一下吧
OC中繼承的實現格式:
@interface 子類名稱 : 父類名稱 @end
記得導入父類頭文件
繼承:
當B類繼承A類, 那麼B類就擁有A類全部的屬性和方法(類方法/對象方法)
優勢:
提升代碼的複用性
可讓類與類之間產生關係, 正是由於繼承讓類與類之間產生了關係因此纔有了多態
缺點: 增長了代碼之間的耦合性
注意:
不要覺得繼承能夠提升代碼的複用性, 之後但凡發現多個類當中有重複代碼就抽取一個父類
只要知足必定的條件咱們才能使用繼承
條件: XXXX 是 XXX / 某某某 is a 某某某 (繼承是 '是' 的關係 接口(協議) 是 '有' 的關係)
方法的重寫:
方法重寫: 子類從父類繼承了父類的方法(行爲) 可是不想用父類的實現體 能夠本身提供新的實現覆蓋掉父類的實現
舉例: 我爸會打人 我從我爸那也繼承了打人的行爲 我爸打人用拳頭打 可是我感受用拳頭打不爽 就能夠用本身的方式去打 (如用板磚砸) 這樣雖然都是打人的方法 可是我用板磚打覆蓋了從我爸那繼承來的用拳頭打 這樣方法名相同 可是方法的實現子類和父類不一樣(子類的實現覆蓋了父類的實現) 就是方法的重寫
在上面例子中咱們來重寫父類學習的方法:
Person類中得學習方法實現:
// 學習 - (void)study{ NSLog(@"學習"); }
工人類重寫父類的學習方法:
// 學習 - (void)study{ NSLog(@"咱們在職人員經過上網來學習"); }
學生類重寫父類的方法:
// 學習 - (void)study{ [super study]; NSLog(@"咱們學生都經過去上課來學習"); }
繼承中方法調用的順序:
一、在本身類中找
二、若是沒有,去父類中找
三、若是父類中沒有,就去父類的父類中
四、若是父類的父類也沒有,就還往上找,直到找到基類(NSObject)
五、若是NSObject都沒有就報錯了
以上若是找到了就執行這個方法,就再也不日後查找了
繼承的注意事項:
super關鍵字:
概念: super是個編譯器的指令符號,只是告訴編譯器在執行的時候,去調誰的方法
做用: 直接調用父類中的某個方法
super在對象方法中,那麼就會調用父類的對象方法 super在類方法中,那麼就會調用父類的類方法
使用場合: 子類重寫父類的方法時想保留父類的一些行爲