OC中的三大特性, 我们已经讲完了封装, 继承, 现在我们来看看最后一个, 多态, 什么是多态呢?? 顾名思义就是有多种形态, 那么在OC中的对象又是怎么样拥有多种形态的呢??? 让我们一起来看看吧~~
例子:
#import <Foundation/Foundation.h> /*********Animal声明**********/ @interface Animal : NSObject - (void)eat; @end /*********Animal声明**********/ @implementation Animal - (void)eat { NSLog(@"Animal----吃东西"); } @end /*********Person声明**********/ @interface Person : Animal @end /*********Person实现**********/ @implementation Person @end int main() { Person *man = [Person new]; //Person类型 [man eat]; return 0; }
输出的结果我们不用想都知道:
2015-01-19 12:37:55.614 a.out[18547:2057354] Animal----吃东西
那到底什么才是多态呢???? 改一下例子:
int main() { Person *man = [Person new]; //Person类型 [man eat]; Animal *women = [Person new]; [women eat]; return 0; }
2015-01-19 12:41:23.053 a.out[18564:2059514] Animal----吃东西 2015-01-19 12:41:23.054 a.out[18564:2059514] Animal----吃东西
解释一下:
在我们的逻辑思维里, 人是动物, 这句话是没错的, 所以在例子里, 拿着一个指针名为women的Animal的指针指向Person对象, 这也是合理的, 所以输出的结果是一致的, 这就是所谓的多态.
比如:
/********Dog声明*********/ @interface Dog : Animal @end /********Dog实现*********/ @implementation Dog - (void)eat { NSLog(@"Dog----在吃东西"); } @end int main() { Person *man = [Person new]; //Person类型 [man eat]; Animal *women = [Person new]; [women eat]; Animal *dog = [Dog new]; [dog eat]; return 0; }
2015-01-19 13:08:00.105 a.out[18609:2065843] Animal----吃东西 2015-01-19 13:08:00.106 a.out[18609:2065843] Animal----吃东西 2015-01-19 13:08:00.106 a.out[18609:2065843] Dog----在吃东西
在前面我们知道了OC是一种弱语法, 就算是遇到逻辑上的错误, 只有一个警告, 不会报错, 所以在多态中也是如此, 注意逻辑上的错误, 比如:
int main() { Person *a = [Dog new]; [a eat]; return 0; }
结果:
Cain:2.第二天 Cain$ cc 15-多态.m -framework Foundation 15-多态.m:44:13: warning: incompatible pointer types initializing 'Person *' with an expression of type 'Dog *' [-Wincompatible-pointer-types] Person *a = [Dog new]; ^ ~~~~~~~~~ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/objc/NSObject.h:62:1: note: class method 'new' is assumed to return an instance of its receiver type ('Dog *') + (instancetype)new; ^ 1 warning generated.
Cain:2.第二天 Cain$ ./a.out 2015-01-19 13:11:53.994 a.out[18628:2068193] Dog----在吃东西这样子是可以运行的, 但在我们的逻辑思维里, 拿一个Person的指针指向Dog合理吗?? 人不是狗, 所以在这里需要我们程序员自己去判断一些逻辑思维, 千万不要乱用多态, 否则陋习一旦养成, 就会祸害终生.
那么多态还有什么有什么用处吗?? 当然有, 比如:
#import <Foundation/Foundation.h> /*********Animal声明**********/ @interface Animal : NSObject - (void)eat; @end /*********Animal声明**********/ @implementation Animal - (void)eat { NSLog(@"Animal----吃东西"); } @end /*********Person声明**********/ @interface Person : Animal @end /*********Person实现**********/ @implementation Person - (void)eat { NSLog(@"Person----人在吃东西"); } @end /********Dog声明*********/ @interface Dog : Animal @end /********Dog实现*********/ @implementation Dog - (void)eat { NSLog(@"Dog----在吃东西"); } @end void eat(Animal *a) { [a eat]; } int main() { Animal *man = [Person new]; eat(man); Animal *dog = [Dog new]; eat(dog); return 0; }
输出结果:
Cain:2.第二天 Cain$ cc 15-多态.m -framework Foundation Cain:2.第二天 Cain$ ./a.out 2015-01-19 13:19:26.999 a.out[18640:2071291] Person----人在吃东西 2015-01-19 13:19:27.000 a.out[18640:2071291] Dog----在吃东西
由于Person和Dog都是继承与Animal这个类, 但它们各自吃东西的方式又不同, 但我们又不想写那么多代码, 那么多态在这里就发挥作用了, 直接写一个函数, 参数类型是它们的父类指针类型, main()函数里创建对象, 并且各自调用各自的吃东西方法, 这样子做, 可以为我们省略很多代码量.
前面我们说了, 如果是遇到不合理的类型时, 那我们应该怎么解决呢? 下面让我们一起来看看:
int main() { Animal *aa = [Dog new]; Dog *dd = (Dog *)aa; [dd run]; return 0; }
Cain:2.第二天 Cain$ cc 15-多态.m -framework Foundation Cain:2.第二天 Cain$ ./a.out 2015-01-19 13:48:21.266 a.out[18809:2085253] Dog----跑起来
多态
1.没有继承就没有多态
2.代码的体现:父类类型的指针指向子类对象
3.好处:如果函数方法参数中使用的是父类类型,可以传入父类、子类对象
4.局限性:
1> 父类类型的变量 不能 直接调用子类特有的方法。必须强转为子类类型变量后,才能直接调用子类特有的方法
好了, 这次我们就讲到这里, 下次我们继续~~~