多态基本概念

  1. 多态在代码中的体现,即为多种形态,必须要有继承,没有继承就没有多态。
  2. 在使用多态时,会进行动态检测,以调用真实的对象方法。
  3. 多态在代码中的体现即父类指针指向子类对象

经典实例讲解

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方法

多态总结

  • 没有继承就没有多态
  • 代码的体现:子类重写父类的方法,父类类型的指针指向子类对象
  • 好处:如果函数方法参数中使用的是父类类型,则可以传入父类和子类对象,而不用再去定义多个函数来和相应的类进行匹配了
  • 局限性:父类类型的变量不能直接调用子类特有的方法,如果必须要调用,则必须强制转换为子类后再调用

其他应用场景

  1. UITableViewCell 的多样式创建