多态

什么是多态?

多态是建立在继承的基础上的,oc中的指针类型变量有两个:一个是编译时类型,一个是运行时类型,编译时类型由声明该变量是使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就有可能出现多态。

先给大家举猫、狗的例子

一共有三个类:Aniaml、Cat、Dog
//Cat、Dog的父类都是Animal
//包含feed方法的咱们先不看**Animal.h**
#import <Foundation/Foundation.h>@interface Animal : NSObject- (void) eat ;- (void) feedall : (Animal*) animal ;- (void) feed ;@end**Animal.m**
#import "Animal.h"@implementation Animal- (void) eat {NSLog(@"动物吃东西") ;
}- (void) feedall:(Animal *)animal {[animal feed];
}@end
**Dog.h**
#import <Foundation/Foundation.h>@interface Dog : NSObject- (void) eat ;- (void) feed ;@end**Dog.m**
#import "Dog.h"@implementation Dog- (void) eat {NSLog(@"狗吃东西");
}- (void) feed {NSLog(@"狗需要喂食");
}@end
**Cat.h**
#import <Foundation/Foundation.h>@interface Cat : NSObject- (void) eat ;- (void) feed ;@end**Cat.m**
#import "Cat.h"@implementation Cat- (void) eat {NSLog(@"猫吃东西");
}- (void) feed {NSLog(@"猫需要喂食");
}@end
**main.m**
#import <Foundation/Foundation.h>
//导入头文件
#import "Animal.h"
#import "Dog.h"
#import "Cat.h"int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...Animal * animal = [[Animal alloc] init];[animal eat];Dog * dog = [[Dog alloc] init];[dog eat];Cat * cat = [[Cat alloc] init];[cat eat];Animal * aniDog = [[Dog alloc] init];[aniDog eat];Animal * aniCat = [[Cat alloc] init];[aniCat eat];[dog feed];[cat feed];}return 0;
}

输出结果

2020-01-30 15:42:56.617314+0800 8.多态[890:29612] 动物吃东西
2020-01-30 15:42:56.617902+0800 8.多态[890:29612] 狗吃东西
2020-01-30 15:42:56.617942+0800 8.多态[890:29612] 猫吃东西
2020-01-30 15:42:56.617968+0800 8.多态[890:29612] 狗吃东西
2020-01-30 15:42:56.617989+0800 8.多态[890:29612] 猫吃东西

前面三个,咱们都没有问题吧!
关键看后两个,aniDog指针很特殊,编译时是Animal类型,运行时却是Dog类型,所以实际调上执行的是Dog类中覆盖的eat方法。指针变量在编译阶段只能调用编译时所具有的方法,但运行时则执行其运行时类型所具有的方法

  oc中允许把一个子类对象直接赋值给一个父类指针变量,不需要任何变量。

当把一个子类对象直接赋值给一个父类指针变量时,编译时和运行时类型不一样,运行时调用该指针变量的方法时,其方法是子类方法而不是父类的方法,这就出现了相同类型的变量调用同一个方法时呈现出多种不同行为特征。

  补充(id):oc中提供了一个id类型,这个id类型可以代表所有对象的类型。就是说,任意类型的对象都可以赋值给id类型变量。

当通过id类型变量来调用方法时,oc将会执行动态绑定,动态绑定,是指oc将会跟踪对象所属类,它会在运行时判断该对象所属类,并在运行时确定需要动态调用的方法,而不是在编译时确定要调用的方法。如上面,程序会在运行时动态检测该变量所指的对象的实际类型为Dog,所以会动态绑定到执行Dog的eat方法。

多态的具体用处

看了上面,你也许还是不知道多态具体的妙处
下面以回合制的卡牌游戏为例来讲解多态的使用。
游戏卡牌英雄分3种职业,分别是战士、法师、术士,不同职业的英雄攻击方式各不相同,我们可以同时上阵5个英雄(比如2个法师2个术士1个战士),轮到我方回合时,上阵的5个英雄轮流发起攻击。
下面我们来看看不使用多态和使用多态两种方式来实现这个需求。

不用多态

每个职业创建一个类,分别实现它们的攻击方法。然后创建一个英雄管理类,在这个类中初始化5个英雄放入一个数组,然后遍历数组取出每个英雄进行攻击。先来看看具体代码吧:

战士类

/*战士*/
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Warrior : NSObject/**战士攻击*/
- (void)warriorAttack;@endNS_ASSUME_NONNULL_END
/*战士*/
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Warrior : NSObject/**战士攻击*/
- (void)warriorAttack;@endNS_ASSUME_NONNULL_END

法师类

/*法师*/
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Mage : NSObject/**法师攻击*/
- (void)mageAttack;@endNS_ASSUME_NONNULL_END
#import "Mage.h"@implementation Mage- (void)mageAttack{// 法师的攻击方式NSLog(@"法师进行攻击");
}@end

术士类

/*术士*/
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Warlock : NSObject/**术士攻击*/
- (void)warlockAttack;@endNS_ASSUME_NONNULL_END
/*术士*/
#import "Warlock.h"@implementation Warlock- (void)warlockAttack{// 术士的攻击方式NSLog(@"术士进行攻击");
}@end

英雄管理类

#import "HeroManager.h"
#import "Warrior.h"
#import "Mage.h"
#import "Warlock.h"@implementation HeroManager
{NSArray *_heroArr;
}- (instancetype)init
{self = [super init];if (self) {[self createHero];[self heroAttack];}return self;
}// 创建英雄
- (void)createHero{// 2个法师Mage *mage1 = [[Mage alloc] init];Mage *mage2 = [[Mage alloc] init];// 2个术士Warlock *warlock1 = [[Warlock alloc] init];Warlock *warlock2 = [[Warlock alloc] init];// 1个战士Warrior *warrior1 = [[Warrior alloc] init];_heroArr = @[mage1,mage2,warlock1,warlock2,warrior1];}// 英雄攻击
- (void)heroAttack{for (NSInteger i = 0; i < _heroArr.count; i++) {if ([_heroArr[i] isKindOfClass:[Warrior class]]) {// 判断如果是战士类型就进行战士攻击Warrior *warrior = (Warrior *)_heroArr[i];[warrior warriorAttack];}else if ([_heroArr[i] isKindOfClass:[Mage class]]) {// 判断如果是法师类型就进行法师攻击Mage *mage = (Mage *)_heroArr[i];[mage mageAttack];}else if ([_heroArr[i] isKindOfClass:[Warlock class]]) {// 判断如果是术士类型就进行术士攻击Warlock *warlock = (Warlock *)_heroArr[i];[warlock warlockAttack];}}
}@end

运行结果如下:

2019-06-27 09:43:46.172172+0800 abc[22549:4026177] 法师进行攻击
2019-06-27 09:43:46.172607+0800 abc[22549:4026177] 法师进行攻击
2019-06-27 09:43:46.172623+0800 abc[22549:4026177] 术士进行攻击
2019-06-27 09:43:46.172635+0800 abc[22549:4026177] 术士进行攻击
2019-06-27 09:43:46.172646+0800 abc[22549:4026177] 战士进行攻击

从上面英雄攻击的方法可以看出,每次攻击时都需要判断当前攻击的英雄是什么职业,然后再调用相应职业的攻击方法。现在只有3个职业,如果是10个职业呢,那这个方法里面就会有10个if……else if的判断,而且如果游戏更新,新增加了一个职业,那么这个方法又要进行改动,又要添加一个else if的判断,程序拓展起来非常的不灵活。

使用多态

使用多态时先创建一个英雄父类,父类里面有个攻击的方法,然后每个职业都继承自这个父类并重写攻击的方法。下面看下具体代码的实现:

/*英雄父类*/
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Hero : NSObject
/**攻击*/
- (void)attack;@endNS_ASSUME_NONNULL_END
#import "Hero.h"@implementation Hero@end

战士类

/*战士*/
#import "Hero.h"NS_ASSUME_NONNULL_BEGIN@interface Harrior : Hero@endNS_ASSUME_NONNULL_END
#import "Harrior.h"@implementation Harrior// 重写父类攻击方法
- (void)attack{// 战士的攻击方式NSLog(@"战士进行攻击");
}@end

法师类

/*法师*/
#import "Hero.h"NS_ASSUME_NONNULL_BEGIN@interface Mage : Hero@endNS_ASSUME_NONNULL_END
#import "Mage.h"@implementation Mage// 重写父类攻击方法
- (void)attack{// 法师的攻击方式NSLog(@"法师进行攻击");
}@end

术士类

/*术士*/
#import "Hero.h"NS_ASSUME_NONNULL_BEGIN@interface Warlock : Hero@endNS_ASSUME_NONNULL_END
#import "Warlock.h"@implementation Warlock// 重写父类攻击方法
- (void)attack{// 术士的攻击方式NSLog(@"术士进行攻击");
}@end

英雄管理类

#import "HeroManager.h"
#import "Warrior.h"
#import "Mage.h"
#import "Warlock.h"@implementation HeroManager
{NSArray *_heroArr;
}- (instancetype)init
{self = [super init];if (self) {[self createHero];[self heroAttack];}return self;
}- (void)createHero{// 2个法师Mage *mage1 = [[Mage alloc] init];Mage *mage2 = [[Mage alloc] init];// 2个术士Warlock *warlock1 = [[Warlock alloc] init];Warlock *warlock2 = [[Warlock alloc] init];// 1个战士Warrior *warrior1 = [[Warrior alloc] init];_heroArr = @[mage1,mage2,warlock1,warlock2,warrior1];}// 英雄攻击
- (void)heroAttack{for (NSInteger i = 0; i < _heroArr.count; i++) {Hero *hero = (Hero *)_heroArr[i];[hero attack];}
}@end

从上面英雄攻击的方法可以看出,当父类指针指向子类时,调用attack方法时它会根据子类的类型去进行不同的攻击,我们完全不用关心也不用判断英雄的职业。这样设计代的话码少了很多,而且就算有10个、100个职业,heroAttack方法里面完全不用改的,新增职业时这里也不需要变动,拓展起来就灵活了很多。

最后

看到这,你明白了吗?

多态秒用这部分来源于简书(作者:一叶知秋0830)
文章地址戳这儿OC中的多态
十分感谢

Objective-C ------ 多态相关推荐

  1. 重拳出击之《JVM》面试官版 (初哥勿看)

    <fonr color = black>JVM发展史,虚拟机发展史模块 java技术体系包括了几个组成部分? javaME.SE.EE分别是什么? 都说JDK7版本是第一个里程碑版本,为什 ...

  2. 【iOS 开发】Objective - C 面向对象 - 方法 | 成员变量 | 隐藏封装 | KVC | KVO | 初始化 | 多态

    一. Objective-C 方法详解 1. 方法属性 (1) OC 方法传参机制 Object-C 方法传参机制 : OC 中得参数传递都是值传递, 传入参数的是参数的副本; -- 基本类型 (值传 ...

  3. iOS完全自学手册——[三]Objective-C语言速成,利用Objective-C创建自己的对象...

    1.前言 上一篇已经介绍了App Delegate.View Controller的基本概念,除此之外,分别利用storyboard和纯代码创建了第一个Xcode的工程,并对不同方式搭建项目进行了比较 ...

  4. 【iOS 开发】Objective-C 运算符

    博客地址 : http://blog.csdn.net/shulianghan/article/details/41624613 参考文章 : 1.[iOS 开发]Object-C 运算符 2.[iO ...

  5. Objective C 基础教程

    复合 使用复合可组合多个对象,使之人工协作. 会同时使用继和复合来创建自己的类. 编程中的复合就好像音乐中的作曲一样:将多个组件组合在一起配合使用. 在Objective-C中,复合是通过包含作为实例 ...

  6. Objective C的那点小语法

    2019独角兽企业重金招聘Python工程师标准>>> 占坑 1,多继承 (新到一个公司,老同事们都使唤你干活,你什么活都干,过了一段时间) 你发现你既可以做android,你也可以 ...

  7. Python Day26:多态、封装、内置函数:__str__、__del__、反射(反省)、动态导入模块...

    ## 多态 ```python OOP中标准解释:多个不同类型对象,可以响应同一个方法,并产生不同结果,即为多态 多态好处:只要知道基类使用方法即可,不需要关心具体哪一个类的对象实现的,以不变应万变, ...

  8. Go 学习笔记(36)— 基于Go方法的面向对象(封装、继承、多态)

    Go 面向对象编程的三大特性:封装.继承和多态. 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式 继承:使得子类具有父类的属性和方法或者重新定义.追加属性和方法等 多态:不同对象中同种行为的不 ...

  9. Objective C内存管理之理解autorelease------面试题

    Objective C内存管理之理解autorelease Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的Aut ...

  10. C#关于面对象多态例子

    //主的喂狗 class Program     {         static void Main(string[] args)         {             //我们来模拟一个主人 ...

最新文章

  1. 伯克利大神一人投中16篇:ICLR 2021论文接收统计出炉
  2. 监督学习-逻辑回归及编程作业(一)
  3. MARSHALL LIBRARY OPENING HOURS
  4. python diango_Django 安装
  5. shop--12.阿里云部署以及域名绑定
  6. jquery 事件对象属性小结
  7. [BZOJ2038] [2009国家集训队] 小Z的袜子(hose) (莫队)
  8. 海量图片去重算法-局部分块Hash算法
  9. ios 手游SDK 开发教程
  10. html转换为pdf的笔顺,正式出台的笔顺标准写法,很全面!(附电子打印版)
  11. windows7到底是多用户多任务操作系统还是单用户多任务操作系统
  12. 【苹果相册推】软件安装ipv6得到可由Apple使用ArrayList tmpMacList
  13. css 背景图片模糊遮罩效果
  14. HTML5+CSS3小实例:黏性小球loading动画
  15. V模型 W模型 H模型
  16. 在Spring Boot中使用数据缓存
  17. C:L1-051 打折 (5分)
  18. linux内置变量大全,(转)linux awk 内置变量使用介绍
  19. 编辑引导扇区修复分区引导解决磁盘分区打不开
  20. 基于图数据库的物联网模型(1)-图数据库与模型设计

热门文章

  1. qt显示温度℃度数°或中文等特殊符号
  2. 划分vlan实验心得体会_计算机网络实验心得体会_计算机网络实验工作感想
  3. mac c语言运行程序,Mac运行C语言
  4. SAP 领料BAPI BAPI_GOODSMVT_CREATE 提示 短缺未限制使用的SL
  5. 模式识别与机器学习(PATTERNnbsp;RECO…
  6. mysql快速复制数据库
  7. phpmywind 解决多语言版本 导航调取问题-5.6之前版本
  8. 强化学习RL学习笔记2-概述(2)
  9. AVL树(LL,RR,LR,RL)
  10. 启动tomcat卡在“信息: Destroying ProtocolHandler”