Objective-C学习篇03—继承
Objective-C學(xué)習(xí)篇03—繼承
大綱:
繼承的基本概念
自定義初始化方法
便利構(gòu)造器方法
重寫(xiě)description方法
?
一 繼承基本概念
程序里的對(duì)象和"人類"的對(duì)象是一樣的,高富帥繼承了父母,自然就擁有了父母所有的資源,子類繼承了父類同樣就擁有了父類所有的屬性和方法,當(dāng)然,父類私有的除外.
我們?cè)诙x一個(gè)新的類的時(shí)候,常常會(huì)遇到要定義的新類是某個(gè)類的擴(kuò)展或者是某個(gè)類的修正等這種情況.如果能夠在已有的類的基礎(chǔ)上定義新類,那么新類的定義將會(huì)變得十分簡(jiǎn)便.
類似于這種,通過(guò)擴(kuò)展或者修改既有的類來(lái)定義新類的方法就叫做繼承(inheritance).在繼承關(guān)系中,被繼承的類(原有的類)就成為父類(superclass),通過(guò)這種繼承關(guān)系得到的新類就叫做子類(subclass).
上面也講到,繼承意味著子類可以得到父類所有的屬性和方法,除此之外,子類還可以為新類:
1.?添加新的實(shí)例變量
2.?追加新的自己特有的方法
3.?重新定義父類中的方法
當(dāng)然,如果子類中只追加新的實(shí)例變量而不變更方法則沒(méi)有任何意義.可以說(shuō),繼承的目的就是要讓子類能做更多父類做不了的事(擴(kuò)展方法).子類中重新定義父類的方法叫做重寫(xiě).分為完全重寫(xiě)和不完全重寫(xiě),這些在后面都會(huì)講到.
繼承的優(yōu)點(diǎn):1> 省略了大量重復(fù)的代碼 ?2>建立起類與類之間的關(guān)系.
缺點(diǎn)在于類間耦合性太強(qiáng)
二 OC中的繼承關(guān)系
1. 在OC中,一旦建立了繼承關(guān)系,子類就可以使用父類中所有的實(shí)例變量和方法.(父類私有的除外)
2. OC中的繼承是單繼承關(guān)系,一個(gè)類只能有一個(gè)父類,但是一個(gè)類可以有n個(gè)子類.
3.?OC中的繼承關(guān)系一定是合理的
4. OC中繼承是單根類繼承,所有類的祖宗類都是NSObject,NSObject是所有類的基類或者根類
5. A 繼承自 B 可以說(shuō),A是B的子類,或者說(shuō)A類是由B類衍生的,衍生類
6.?使用繼承的好處:如果一些類在定義的時(shí)候,發(fā)現(xiàn)他們有很多的實(shí)例變量或者方法是重復(fù)的(共同的特征),此時(shí)就可以把這些實(shí)例變量或者方法抽象出一個(gè)新的類作為這些類的父類,這樣我們?cè)诙x一個(gè)類的時(shí)候,直接將要的定義的類繼承自這個(gè)父類,就能省去很多重復(fù)的代碼,只需要在子類中添加自己獨(dú)有的特征和方法.
7. 父類中被@public和@protected修飾的實(shí)例變量,子類中可以直接訪問(wèn),而被@provate(私有的)修飾的實(shí)例變量子類不能直接訪問(wèn),只能通過(guò)方法訪問(wèn)
8. 子類在調(diào)用方法時(shí)優(yōu)先去自己的類里面找,找到了就直接調(diào)用,找不到就去父類中找,找到就調(diào)用,找不到就直接向上找,直到最終找到NSObject,如果實(shí)現(xiàn)就調(diào)用,沒(méi)有實(shí)現(xiàn)就Crash
9. 重寫(xiě)父類的方法,一種是完全重寫(xiě),不完全重寫(xiě)時(shí)需要在方法中使用super調(diào)用父類對(duì)方法的實(shí)現(xiàn)
?
使用繼承時(shí)要注意的問(wèn)題
代碼演示:
首先,創(chuàng)建一個(gè)汽車Car類,讓它繼承自NSObject類
Car.h
@interface Car : NSObject // 汽車的特征 {@publicNSString *_color; //顏色@protectedNSString *_brand; //品牌
@privateNSInteger _wheel; //輪子 }// 車的行為 - (void)run; - (void)carShock;
// 實(shí)例變量的setter getter方法 - (void)setColor:(NSString *)color; - (NSString *)color;- (void)setBrand:(NSString *)brand; - (NSString *)brand;- (void)setWheel:(NSInteger)wheel; - (NSInteger)wheel; @end
Car.m
@implementation Car - (void)run {NSLog(@"車在跑"); }- (void)carShock {NSLog(@"車震是什么感覺(jué),沒(méi)試過(guò)"); }- (void)setColor:(NSString *)color {_color = color; }- (NSString *)color {return _color; }- (void)setBrand:(NSString *)brand {_brand = brand; }- (NSString *)brand {return _brand; }- (void)setWheel:(NSInteger)wheel {_wheel = wheel; }- (NSInteger)wheel {return _wheel; }@end
上面我們定義了一個(gè)汽車Car的類,,使它具有顏色,品牌,輪子的屬性,具有跑和車震兩種行為(方法).現(xiàn)在,我們給卡車Truck增加一個(gè)最大載貨量的屬性和輸出自身信息的方法,同時(shí)又包含Car這些屬性和方法,那么我們就要使用繼承;
這個(gè)時(shí)候利用繼承的思想,我們只需要新建一個(gè)類,讓它繼承自Car這個(gè)類,新類中寫(xiě)自己特有的方法和屬性.
新建一個(gè)Truck類,繼承自Car:
Truck.h
@interface Truck : Car {// NSString *_color; error 子類中不能定義和父類同名的實(shí)例變量CGFloat _maxLoad; //最大載貨量 }- (void)setMaxLoad:(CGFloat)manLoad; - (CGFloat)maxLoad;// 描述卡車信息的方法 - (void)describeTruck; - (void)run; // 子類中可以定義和父類同名的方法,這種形式叫做方法的重寫(xiě)//那么,為什么要進(jìn)行方法的重寫(xiě)呢?因?yàn)楦割愄峁┑姆椒ú荒軡M足子類的需求// 重寫(xiě)父類的方法有兩種,一種是完全重寫(xiě)父類的方法,另一種是不完全重寫(xiě)的方法@end
Truck.m
@implementation Truck // _maxLoad的setter getter方法 - (void)setMaxLoad:(CGFloat)manLoad {_maxLoad = manLoad; }- (CGFloat)maxLoad {return _maxLoad; }// 描述卡車信息的方法 - (void)describeTruck {NSLog(@"%@ %@ %ld %.2f", _color, _brand, self.wheel, _maxLoad); } // 注意:由于 _wheel被private修飾,不能在子類中直接訪問(wèn),需要用self// 重寫(xiě)父類run的方法 // 如果在重寫(xiě)父類方法時(shí),沒(méi)有調(diào)用父類的方法實(shí)現(xiàn)就叫做完全重寫(xiě) - (void)runNSLog(@"卡車在奔跑"); }// 重寫(xiě)車震的方法 - (void)carShock {// super 編譯器指令,用于調(diào)用父類的方法,適用于想保留父類中某些方法的情況[super carShock];NSLog(@"卡車不好震"); }@end
回到main中.
// 創(chuàng)建一個(gè)大卡車的對(duì)象 Truck *truc = [[Truck alloc] init];// color brand wheel是從父類繼承過(guò)來(lái)的 truc.color = @"藍(lán)色"; // 顏色 truc.brand = @"東風(fēng)"; // 品牌 truc.wheel = 12; // 輪子// maxLoad是子類特有的 truc.maxLoad = 120.0;// 載重量// 調(diào)用父類的方法 // [truc carShock];[truc run];// 調(diào)用描述卡車的方法[truc describeTruck];
// 調(diào)用車震的方法[truc carShock];
打印結(jié)果:
2015-11-26 22:46:44.741 OCLessonInherit-03[1759:364404]?卡車在奔跑
2015-11-26 22:46:44.742 OCLessonInherit-03[1759:364404]?藍(lán)色東風(fēng)?12 120.00
2015-11-26 22:46:44.742 OCLessonInherit-03[1759:364404]?沒(méi)震過(guò),不知道什么感覺(jué)
2015-11-26 22:46:44.742 OCLessonInherit-03[1759:364404]?卡車不好震
??
三 初始化方法
if (self) {// 初始化設(shè)置_taxiMeter = @"計(jì)價(jià)器"; } // 返回初始化完成的對(duì)象return self; }
初始化過(guò)程:
???????? 初始化時(shí),先調(diào)用父類的[super init]方法(向上遞歸到NSObject類中的初始化方法),使用self接收結(jié)果,然后根據(jù)self中的值判斷是否為nil,決定要不要初始自己的實(shí)例變量;如果為nil,說(shuō)明父類的初始化方法失敗了,就不再對(duì)自身實(shí)例變量初始化,如果不為nil,說(shuō)明父類初始化方法成功了,再對(duì)自身實(shí)例變量進(jìn)行初始化
2.自定義初始化方法
命名規(guī)范:
??? 1. 一定是對(duì)象方法,以減號(hào) - 開(kāi)頭
??? 2. 返回值類型是?id 類型(最好寫(xiě)id類型) 或者是當(dāng)前的類類型
??? 3. 必須以?initWith 開(kāi)頭
??? 4. 自定義初始化方法分為兩種:完全自定義初始化 與 不完全初始化方法
?示例:
不完全初始化方法:
// 只初始化姓名和年齡 - (id)initWithName:(NSString *)name age:(NSInteger)age {if (self = [super init]) {_name = name;_age = age;}return self; }? ? ??完全自定義初始化:
//?初始化全部的實(shí)例變量
- (id)initWithName:(NSString *)name age:(NSInteger)age height:(CGFloat)height {if (self = [super init]) {
_name = name;_age = age;_height = height;}return self; }
3.便利構(gòu)造器方法
命名規(guī)范
1. 遍歷構(gòu)造器方法一定是一個(gè)類方法,以加號(hào)開(kāi)頭(+)
2. 返回值類型一定是?id類型
3. 以類名小寫(xiě)開(kāi)頭?+With+實(shí)例變量名去掉下劃線且首字母大寫(xiě)
注意:
4. 便利構(gòu)造器又叫做工廠方法,用于快捷快速地創(chuàng)建對(duì)象
5. 便利構(gòu)造器方法的實(shí)質(zhì): 在方法內(nèi)部把一個(gè)創(chuàng)建好的對(duì)象作為方法的返回值
6.?便利構(gòu)造器方法要和自定義初始化方法配套使用
?
示例(對(duì)應(yīng)上面列舉的兩種自定義初始化方法):
+ (id)personWithName:(NSString *)name age:(NSInteger)age {// 將一個(gè)創(chuàng)建好的對(duì)象作為便利構(gòu)造器方法的返回值return [[Person alloc] initWithName:name age:age]; }
+ (id)personWithName:(NSString *)name age:(NSInteger)age hight:(CGFloat)hight {
return [[Person alloc] initWithName:name age:age height:hight]; }@end
main
Person *p = [[Person alloc] init];NSLog(@"%@ - %ld - %.2f", p.name, p.age, p.height);//調(diào)用自定義初始化方法Person *p1 = [[Person alloc] initWithName:@"吳邪"];NSLog(@"%@ - %ld - %.2f", p1.name, p1.age, p1.height);Person *p2 = [[Person alloc] initWithName:@"花千骨" age:18];NSLog(@"%@ - %ld - %.2f", p2.name, p2.age, p2.height);
// 調(diào)用完全初始化方法Person *p3 = [[Person alloc] initWithName:@"白子畫(huà)" age:22 height:70];NSLog(@"%@ - %ld - %.2f", p3.name, p3.age, p3.height);// 調(diào)用便利構(gòu)造器方法Person *p4 = [Person personWithName:@"殺阡陌"];NSLog(@"%@ - %ld - %.2f", p4.name, p4.age, p4.height);Person *p5 = [Person personWithName:@"東方彧卿" age:15];p5.name = @"糖寶";p5.height = 0.3;NSLog(@"%@ - %ld - %.2f", p5.name, p5.age, p5.height);Person *p6 = [Person personWithName:@"單春秋" age:26 hight:1.65];NSLog(@"%@ - %ld - %.2f", p6.name, p6.age, p6.height);
以下是完整的代碼:
Person.h
#import "Car.h" @interface Person : Car{NSString *_name;NSInteger _age;CGFloat _height; }- (void)setName:(NSString *)name; - (NSString *)name;- (void)setAge:(NSInteger)age; - (NSInteger)age;- (void)setHeight:(CGFloat)height; - (CGFloat)height;// 自定義初始化方法 - (id)initWithName:(NSString *)name; - (id)initWithName:(NSString *)name age:(NSInteger)age; - (id)initWithName:(NSString *)name age:(NSInteger)age height:(CGFloat)height;// 寫(xiě)一個(gè)遍歷構(gòu)造器的類方法 + (id)personWithName:(NSString *)name; + (id)personWithName:(NSString *)name age:(NSInteger)age; + (id)personWithName:(NSString *)name age:(NSInteger)age hight:(CGFloat)hight;@end #import "Person.h" @implementation Person - (void)setName:(NSString *)name {_name = name; }
- (NSString *)name {return _name; } - (void)setAge:(NSInteger)age {_age = age; }- (NSInteger)age {return _age; }- (void)setHeight:(CGFloat)height {_height = height; }- (CGFloat)height {return _height; }// 自定義初始化方法 // 無(wú)論是哪種初始化方法,都要首先判斷下父類有沒(méi)有有初始化成功 - (id)initWithName:(NSString *)name {if (self = [super init]) {_name = name;}return self; }- (id)initWithName:(NSString *)name age:(NSInteger)age {if (self = [super init]) {_name = name;_age = age;}return self; }- (id)initWithName:(NSString *)name age:(NSInteger)age height:(CGFloat)height {if (self = [super init]) {
_name = name;_age = age;_height = height;}return self; }
+ (id)personWithName:(NSString *)name {
// 便利構(gòu)造器的實(shí)質(zhì)就是在便利構(gòu)造器方法中創(chuàng)建一個(gè)對(duì)象,然后把這個(gè)對(duì)象作為返回值返回// 遍歷構(gòu)造器方法一定要和自定義初始化方法配合使用Person *p = [[Person alloc] initWithName:name];return p;}+ (id)personWithName:(NSString *)name age:(NSInteger)age {// 將一個(gè)創(chuàng)建好的對(duì)象作為便利構(gòu)造器方法的返回值return [[Person alloc] initWithName:name age:age]; }+ (id)personWithName:(NSString *)name age:(NSInteger)age hight:(CGFloat)hight {
return [[Person alloc] initWithName:name age:age height:hight]; } @end
?
轉(zhuǎn)載于:https://www.cnblogs.com/zmc815/p/5325815.html
總結(jié)
以上是生活随笔為你收集整理的Objective-C学习篇03—继承的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2021-07-15 声音一些基本概念
- 下一篇: mysql 1033 frm_修复mys