类的继承(续)
- 方法的覆盖(overriding)
子类的方法若跟父类的方法名一样,则子类的方法会覆盖掉父类的方法,最终执行子类的方法。
一个例子,只有print方法的子类和父类
#import <Foundation/Foundation.h>
@interface BaseClass : NSObject
- (void) print;
@end
@implementation BaseClass
- (void)print {
NSLog(@"print in BaseClass");
}
@interface InheritClass : BaseClass
- (void)print;
@end
@implementation InheritClass
- (void)print {
NSLog(@"print in InheritClass");
}
int main(int argc, const char *argv[]) {
@autoreleasepool {
BaseClass *base = [ [BaseClass alloc] init ];
InheritClass *inherit = [ [InheritClass alloc] init ];
[base print];
[inherit print];
}
return 0;
}
输出结果为: print in BaseClass
print in InheritClass
- 如果出现方法的覆盖,但是我们又想要用父类的方法那怎么办?
** 用super
关键字。**
super
跟self
很像,都是对当前对象的引用(对自身的引用)。
不一样的是,super
会把当前的对象当做父类对象。
举个例子:在上述代码中,加入一行[super print]
即可
int main(int argc, const char *argv[]) {
@autoreleasepool {
BaseClass *base = [ [BaseClass alloc] init ];
InheritClass *inherit = [ [InheritClass alloc] init ];
[base print];
[inherit print];
[super print];
}
return 0
}
输出结果是:print in BaseClass
print in InheritClass
print in BaseClass
- 两个关键字
id
跟instancetype
e.g.
#import <Foundation/Foundation.h>
@interface A : NSObject
+ (A*)factoryMethod;//工厂方法可以创建自身类型的对象。工厂方法定义成一个类方法(加号开头)
//用来创建当前类的实例对象,所以返回类型是个指针(对象)
- (void)methodA;//这个是实例方法
@end
@implementation A
+ (A*)factoryMethod {
return [[A alloc] init];//工厂方法的实现(作用)就是返回一个生成的实例对象
}
- (void)methodA {
NSLog(@"Call MethodA!");//一个简单的实例方法的实现,往控制台输出东西
}
@end
@interface B : A
- (void)methodB;
@end
@implementation B
- (void)methodB {
NSLog(@"Call MethodB!");
}
@end
int main(int argc, const char *argv[]) {
@autoreleasepool {
A *a = [A factoryMethod];//调用类A的工厂方法创建类A的实例a
B *b = [B factoryMethod];//虽然B继承了A,但是这里调用B的工厂方法是有问题的
}//类B的工厂方法返回值还是类A,因为在定义类A的工厂方法时把返回值写死了
return 0;//在实现里也把返回值写死了,只能返回类A的实例对象
}
解决办法:在类A中对工厂方法的声明和实现都使用id
类型
@interface A : NSObject
+ (id)factoryMethod;
-(void)methodA;
@end
@implementation A
+ (id)factoryMethod {
return [[self class] alloc] init];//注意这里,使用了[self class]这条消息
}
- (void)methodA {
NSLog(@"Call MethodA!");
}
@end
使用id会有个问题,因为编译器不知道返回的具体类型,所以不能做静态语法检测。
比如在main方法里写[[A factoryMethod] methodB]
,这其实是错的,因为类A根本就没有methodB ,但是却能编译通过了,因为编译器不知道工厂方法的返回值类型,所以不知道你返回的对象有没有methodB ,就默认通过了。
解决办法:使用instancetype
类型。它比较特殊,只能用做方法的返回值来用。** 它表示返回值是这个方法所在类的类型。**
若用instancetype
代替类A工厂方法的返回类型id
,
@interface A : NSObject
+ (instancetype)factoryMethod;
若还在main方法里写[[A factoryMethod] methodB]
,这时编译器就会报错了,因为instancetype
表示了[A factoryMethod]
的返回值为factoryMethod
这个方法所在类的类型 ,即类A 。类A没有methodB,当然会报错。
id
虽然灵活,却可能瞒混编译器,隐藏一些bug,所以有时可以用instancetype
代替 。instancetype
有种硬点的意思。