在OC 中有父類和子類的概念,沒有父類(超類->super class)的類位於類層次結構的最頂層,成爲根(root)類,OC中可以定義自己的根類,但不建議這麼做。定義了一個新類,會從父類繼承些屬性。比如,父類的非私有變量和方法都會成爲新類定義的一部分,子類可以直接訪問這些方法和實例變量。
下面舉個例子,首先定義一個類ClassA,再定義一個類ClassB:
#import <Foundation/Foundation.h>
//ClassA的聲明
@interface ClassA : NSObject
{
int x;
}
-(void) initVar;
@end
//ClassA 的實現
@implementation ClassA
-(void) initVar
{
x = 100;
}
@end
//聲明ClassB
@interface ClassB : ClassA
-(void) printVar;
@end
@implementation ClassB
-(void) printVar
{
NSLog(@"x=%i",x);
}
@end
ClassA ,ClassB ,NSObject 幾個類之間的關係如下圖:
如上圖: NSObject 是ClassA和ClassB的父類。由於ClassB是ClassA的子類,因此它繼承了ClassA的共有實例變量和方法:
其實像alloc , init 方法在使用時都未定義過,使用的時候都是從NSObject類中繼承過來的。
注意:1.類的每個對象都擁有自己的實例變量,即使這些實例變量是繼承來的。
2.繼承的概念是作用於整個繼承鏈的。
1.通過繼承添加新方法
(1)我們想寫一個矩形的類, 同時寫一個正方形類作爲矩形的子類,下面爲Recangle, Square的生命和實現代碼:
#import <Foundation/Foundation.h>
@interface Rectangle : NSObject
@property int width, height;
-(int) area;
-(int) perimeter;
@end
//Rectangle.m
#import "Rectangle.h"
@implementation Rectangle
@synthesize width, height;
-(void)setWidth:(int)w andHeight:(int)h
{
width = w;
height = h;
}
-(int)area
{
return width * height;
}
-(int)perimeter
{
return 2*(width + height);
}
@end
//Square.h
#import <Foundation/Foundation.h>
#import "Rectangle.h"
@interface Square : Rectangle
-(void) setSide: (int)s;
-(int) side;
@end
//Square.m
#import "Square.h"
@implementation Square: Rectangle
-(void) setSide: (int)s
{
[self setWidth: s andHeight: s];
}
-(int) side
{
return self.width;
}
@end
#import <Foundation/Foundation.h>
#import "Square.h"
int main ()
{
@autoreleasepool {
Square *mySquare = [[Square alloc] init];
[mySquare setSide:10];
NSLog(@"Square s = %i", [mySquare side]);
NSLog(@"Area = %i, Perimeter = %i", [mySquare area], [mySquare perimeter]);
}
return 0;
}
square方法雖然是Rectangle類的子類,但是因爲width是私有的,故需要通過繼承Rectangle的set方法來或缺。這種定義square類的方式是OC中的基本技術,即擴展自己或其他人以前實現的類,使其適合自己的需求。
2.重寫方法
前面提到過,不能通過繼承刪除或減少方法,但可以利用重寫更繼承方法的定義。所謂重寫:即子類重現父類中的某個方法,覆蓋父類以前的方法(方法的返回型和參數數目都要相同)。
下面的例子說明重寫:
<span style="font-size:14px;">#import <Foundation/Foundation.h>
//ClassA的聲明
@interface ClassA : NSObject
{
int x;
}
-(void) initVar;
@end
//ClassA 的實現
@implementation ClassA
-(void) initVar
{
x = 100;
}
@end
//聲明ClassB
@interface ClassB : ClassA
-(void) initVar;
-(void) printVar;
@end
@implementation ClassB
-(void) initVar
{
x =200;
}
-(void) printVar
{
NSLog(@"x=%i",x);
}
@end
int main ()
{
@autoreleasepool {
ClassB *b = [[ClassB alloc] init];
[b initVar];
[b printVar];
}
return 0;
}</span>
運行結果x = 200; 顯然ClassB中的initVar 方法覆蓋了父類中的initVar方法。
總結:
(1)繼承的優點:
a. 抽取重複代碼,簡歷類之間的關係。
b. 子類可以擁有父類中所有成員變量和方法。
c. 基本上所有類的根類都是NSObject。
(2)注意:
a. 父類必須聲明在子類前面。
b. 不允許子類和父類有相同名稱的成員變量。
c. 調用某個方法時,優先去當前類中找,如果找不到,去父類中找。
(3)重寫:
子類重新實現父類中的某個方法,覆蓋父類以前的方法。
(4)什麼時候創建子類:
a. 希望繼承一個類的函數,或許加入一些新的方法和實例變量。
b. 希望創建一個類的特別版本(圖形對象的特定類型)。
c. 希望通過覆寫一個或多個方法來改變類的默認行爲。