关于OC中的多态编程——1
慢慢从oc转向swift才是王道
使用对象方法
在开始的时候先来看看简单的例子:
1、定义三个类:Shape、Circle、Rectangle。其中Circle和Rectangle是Shape的子类,如下所示:
//---------------@interface section---------------
@interface Shape : NSObject
-(void) draw;
@end
@interface Circle : Shape
-(void)draw;
@end
@interface Rectangle : Shape
-(void)draw;
@end
其中每个类中都单独定义了一个draw方法。
实现如下所示:
@implementation Shape
-(void)draw
{
NSLog(@"Draw a shape.\n");
}
@end
@implementation Circle
-(void)draw
{
NSLog(@"Draw a Circle.\n");
}
@end
@implementation Rectangle
-(void)draw
{
NSLog(@"Draw a Rectangle.\n");
}
@end
在调用时,先定义每种对象的指针:
Shape* s1 = [[Shape alloc]init],*s2 = [[Shape alloc]init];
Circle* c1 = [[Circle alloc]init];
Rectangle* r1 = [[Rectangle alloc]init];
先来看看单独调用每一个对象的draw方法:
NSLog(@"分别向三个不同对象指针传递相同消息");
[s1 draw];
[c1 draw];
[r1 draw];
得到的输出如下:
分别向三个不同对象指针传递相同消息
2016-03-30 16:21:18.865 Polymorphism2[2101:58647] Draw a shape.
2016-03-30 16:21:18.865 Polymorphism2[2101:58647] Draw a Circle.
2016-03-30 16:21:18.865 Polymorphism2[2101:58647] Draw a Rectangle.
现在来看看,如果将之前定义的s1分别赋值为c1和r1,能否成功:
NSLog(@"把父类指针指向子类的尝试");
NSLog(@"Shape指针指向Circle类对象,然后通过父类指针调用draw");
s1 = c1;
[s1 draw]; //出现的是子类行为。
NSLog(@"Shape指针指向Rectangle.");
s1 = r1;
[s1 draw]; //出现的是子类行为。
//结论:父类指针和id有同样的效果(对于它里面的子类而言),这里的就是向上造型(up-casting),可以将子类转换为父类类型。
输出如下:
把父类指针指向子类的尝试
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] Shape指针指向Circle类对象,然后通过父类指针调用draw
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] Draw a Circle.
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] Shape指针指向Rectangle.
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] Draw a Rectangle.
证明子类指针类型已经向父类指针类型转换成功了,所以才可以进行赋值,并且当父类指针指向了子类对象时,子类对象的行为还是没有变化,证明OC的运行时系统中对每一个特定的对象都在进行这原来归属类的追踪。
NSLog(@"如果用子类指针指向父类呢?答案是不行。"); //c1 = s1; 不行,无法进行向下的类型转换将s1转换为c1。
为什么不能将父类对象指针赋值给子类呢?原因如上面注释所述。
如果用书上例子中的,分别将三个对象指针赋值给id类型指针,再使用该id指针调用每个类对象的方法:
NSLog(@"若换用id来指向这些类型,效果如何呢?");
id someKindOfObject;
someKindOfObject = s2;
[someKindOfObject draw];
someKindOfObject = c1;
[someKindOfObject draw];
someKindOfObject = r1;
[someKindOfObject draw];
NSLog(@"结论是:效果一样");
输出如下:
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] 若换用id来指向这些类型,效果如何呢?
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] Draw a shape.
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] Draw a Circle.
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] Draw a Rectangle.
2016-03-30 16:21:18.866 Polymorphism2[2101:58647] 结论是:效果一样
换用Protocol,在每个类实现特定行为:
协议如下所示,其中声明了一个draw方法:
@protocol MyDrawingProtocol <NSObject>
-(void)draw;
@end
类接口如下所示,这里面没有再次声明各自单独的draw方法了:
@interface Shape : NSObject <MyDrawingProtocol>
@end
@interface Circle : Shape
@end
@interface Rectangle : Shape
@end
因为Circle和Rectangle都继承自Shape,默认情况下它们也都遵从MyDrawingProtocol协议,所以直接在它们的实现文件中添加draw方法是没有问题的:
@implementation Shape
-(void)draw
{
NSLog(@"Draw a shape.\n");
}
@end
@implementation Circle
-(void)draw
{
NSLog(@"Draw a Circle.\n");
}
@end
@implementation Rectangle
-(void)draw
{
NSLog(@"Draw a Rectangle.\n");
}
@end
使用的时候也和在类中单独声明方法的情况一样。
但需要注意的是:
继承中的协议方法,也是可以继承的,这本身是由继承的特点决定的。当子类中没有实现协议方法时,并不会报错,因为并没有特别指定子类遵从某个协议。