多态基本概念
- 多态在代码中的体现,即为多种形态,必须要有继承,没有继承就没有多态。
- 在使用多态时,会进行动态检测,以调用真实的对象方法。
- 多态在代码中的体现即父类指针指向子类对象
经典实例讲解
1 、Animal父类
Animal.h
1 2 3 4 5
| #import <Foundation/Foundation.h>
@interface Animal : NSObject - (void) eat; @end
|
Animal.m
1 2 3 4 5 6
| #import "Animal.h" @implementation Animal - (void)eat{ NSLog(@"all animals need to eat food"); } @end
|
2 、cat子类
1 2 3 4 5 6
| #import <Foundation/Foundation.h> #import "Animal.h"
@interface Cat : Animal - (void) eat; @end
|
1 2 3 4 5 6
| #import "Cat.h" @implementation Cat - (void)eat{ NSLog(@"cat need to eat fish"); } @end
|
3、dog子类
1 2 3 4 5 6
| #import <Foundation/Foundation.h> #import "Animal.h"
@interface Dog : Animal - (void) eat; @end
|
1 2 3 4 5 6
| #import "Dog.h" @implementation Dog - (void)eat{ NSLog(@"dog need to eat bome"); } @end
|
4、master类
我们再定义一个Master类,用来喂养宠物
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #import <Foundation/Foundation.h> #import "Animal.h" #import "Cat.h" #import "Dog.h" @interface Master : NSObject{ NSString *_name; } //扩展性不高,当我们需要添加一个新的宠物的时候还要定义对应的一个方法 //所以这时候就可以使用多态技术了 //- (void)feedFoodForCat:(Cat *)cat; //- (void)feedFoodForDog:(Dog *)dog; - (void)feedFoodForPets:(Animal *)pet; @end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #import "Master.h"
@implementation Master /* - (void)feedFoodForCat:(Cat *)cat{ [cat eat]; } - (void)feedFoodForDog:(Dog *)dog{ [dog eat]; } */ - (void)feedFoodForPets:(Animal *)pet{ [pet print]; } @end
|
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #import <Foundation/Foundation.h> #import "Master.h" #import "Cat.h" #import "Dog.h"
int main(int argc, const charchar * argv[]) { @autoreleasepool { Master *person =[[Master alloc] init]; Cat *cat = [[Cat alloc] init]; Dog *dog = [[Dog alloc] init]; //多态的定义 /* Cat *p1 = [[Cat alloc] init]; Dog *p2 = [[Dog alloc] init]; [person feedFoodForPets:p1]; [person feedFoodForPets:p2]; */ //通过控制台输入的命令来控制喂养那只宠物 int cmd; do{ scanf("%d",&cmd); if(cmd == 1){ [person feedFoodForPets:cat]; }else if(cmd == 2){ [person feedFoodForPets:dog]; } }while (1); } return 0; }
|
样例是猫和狗两种宠物的喂食问题。主人Master类中有一个操作喂食的方法,如果不使用多态机制,(即代码中注释部分),就需要给猫和狗分别提供特有的喂食方法声明与实现。
1 2 3 4 5 6 7 8 9 10 11
| //- (void)feedFoodForCat:(Cat *)cat; //- (void)feedFoodForDog:(Dog *)dog; /* - (void)feedFoodForCat:(Cat *)cat{ [cat eat]; } - (void)feedFoodForDog:(Dog *)dog{ [dog eat]; } */
|
这种设计是不友好的。为什么呢?因为当master新增宠物时需要新增对应的喂养方法,如果宠物过多,则会导致master类过于臃肿。这个时候,利用多态机制,在Master类中提过一个参数为父类animal类型的喂食接口,在实际调用中将特定的子类实例作为参数传递进来就可以解决问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| - (void)feedFoodForPets:(Animal *)pet;
- (void)feedFoodForPets:(Animal *)pet{ [pet print]; } //父类指针指向子类对象
//实际使用 Master *person =[[Master alloc] init];
Cat *cat = [[Cat alloc] init]; Dog *dog = [[Dog alloc] init]; [person feedFoodForPets:cat]; [person feedFoodForPets:dog]; //cat、dog表面上是Animal类型,但是实际类型是Animal的子类类型,所以会调用他们自己对应的eat方法
|
多态总结
- 没有继承就没有多态
- 代码的体现:子类重写父类的方法,父类类型的指针指向子类对象
- 好处:如果函数方法参数中使用的是父类类型,则可以传入父类和子类对象,而不用再去定义多个函数来和相应的类进行匹配了
- 局限性:父类类型的变量不能直接调用子类特有的方法,如果必须要调用,则必须强制转换为子类后再调用
其他应用场景
- UITableViewCell 的多样式创建