继承的特点
Objective-C的继承通过父类的语法实现,实现继承的类被称为子类,被继承的类被称为父类,有的也称其为基类、超类。 Objective-C里子类继承父类的语法格式如下:
@interface SubClass : SuperClass {
// 成员变量定义
}
// 方法定义部分
@end
继承关系本质是一种“由一般到特殊”的关系,子类继承父类,子类是一种特殊的父类。
当子类扩展父类时,子类可以继承得到父类的如下东西:
下程序示范了子类继承父类的特点。
#import <Foundation/Foundation.h>
@interface FKFruit : NSObject
@property (nonatomic, assign) double weight;
- (void) info;
@end;
// FKApple只是一个空类,它是FKFruit的子类
@interface FKApple : FKFruit
@end
@implementation FKFruit
- (void) info {
NSLog(@"我是一个水果!重%g g", _weight);
}
@end
@implementation FKApple
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
// 创建FKApple对象
FKApple* a = [[FKApple alloc] init];
// FKApple对象本身没有weight属性
// 因为FKFruit有weight属性,也可以访问FKApple对象的weight属性
a.weight = 56;
// 调用FKApple对象的info方法
[a info];
}
}
Objective-C语言摒弃了C++语言中难以理解的多继承特征,即每一个类最多只有一个直接父类,但Objective-C类可以有无限多个间接父类。
重写父类的方法
子类扩展了父类,子类是一个特殊的父类。大部分时候,子类总是以父类为基础,额外增加新的Field和方法。但是有时候,子类需要重写父类的方法。 当子类要重写父类的方法时,子类接口部分并不需要重新声明要重写的方法,只要在类实现部分直接重写该方法即可。 例:
#import <Foundation/Foundation.h>
@interface FKBrid : NSObject
- (void) fly;
@end
// 声明FKOsrich类接口
@interface FKOsrich : FKBrid
@end
@implementation FKBrid
- (void) fly {
NSLog(@"我能在天上飞!");
}
@end
// 实现FKOsrich类
@implementation FKOsrich
// 重写fly方法
- (void) fly {
NSLog(@"我只能在地上跑!");
}
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
// 创建FKOsrich对象
FKOsrich* os = [[FKOsrich alloc] init];
// 执行os的fly方法
[os fly];
}
}
运行结果:
2022-05-18 20:21:33.494426+0800 oc.programme[55904:1982194] 我只能在地上跑!
Program ended with exit code: 0
super关键字
super是Objective-C提供的一个关键字,super用于限定该对象调用它从父类继承得到的方法和属性。 正如self不能出现在类方法中一样,super也不能出现的类方法中。
例如,我们为上面的FKOsrich类添加一个方法,在这个方法中使用super调用FKBrid被覆盖的fly方法。
- (void) callOverrideMethod {
// 在子类方法中通过super显式调用父类被覆盖的实例方法
[super fly];
}
当子类继承父类时,子类可以获得父类中定义的成员变量,因此,子类接口部分不允许定义与父类接口部分重名的成员变量。
需要指出的是,在类实现部分定义的成员变量将被限制在该类的内部,因此,父类在类实现部分定义的成员变量对子类没有任何影响。 反过来也一样,在子类实现部分定义的成员变量也不受父类接口部分成员变量的影响。
当子类实现部分定义了与父类同名的成员变量,子类的成员变量就会隐藏父类的成员变量。
例:
#import <Foundation/Foundation.h>
@interface FKParent : NSObject {
int _a;
}
@property int a;
@end
@interface FKSub : FKParent
- (void) accessOwner;
@end
@implementation FKParent
- (id) init {
if (self = [super init]) {
self.a = 5;
}
return self;
}
@end
@implementation FKSub {
int _a;
}
- (id) init {
if (self = [super init]) {
self->_a = 7;
}
return self;
}
- (void) accessOwner {
NSLog(@"子类实现部分成员变量:%d", _a);
NSLog(@"父类被隐藏的成员变量:%d", super.a);
}
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
FKSub* sub = [[FKSub alloc] init];
[sub accessOwner];
}
}
上面程序通过super关键字强制指定调用父类的a属性(实际上就是getter方法返回值)。 运行结果
2022-05-18 21:22:38.209228+0800 oc.programme[56528:2010908] 子类实现部分成员变量:7
2022-05-18 21:22:38.209443+0800 oc.programme[56528:2010908] 父类被隐藏的成员变量:5
Program ended with exit code: 0
从上面的运行结果可以看到:子类实现部分定义与父类同名的成员变量,只是隐藏父类的成员变量,虽然程序只是创建一个FKSub对象,但该对象内部依然有两块内存来保存_a的成员变量,一块内存保存父类中被隐藏的_a成员变量,可以通过父类中定义的方法来访问;一块是保存子类实现部分定义的_a成员变量,可以在子类方法中访问。
|