Objective

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----吃东西



解释一下:

在我们的逻辑思维里, 人是动物, 这句话是没错的, 所以在例子里, 拿着一个指针名为womenAnimal的指针指向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----在吃东西

由于PersonDog都是继承与Animal这个类, 但它们各自吃东西的方式又不同, 但我们又不想写那么多代码, 那么多态在这里就发挥作用了, 直接写一个函数, 参数类型是它们的父类指针类型, main()函数里创建对象, 并且各自调用各自的吃东西方法, 这样子做, 可以为我们省略很多代码量.


前面我们说了, 如果是遇到不合理的类型时, 那我们应该怎么解决呢? 下面让我们一起来看看:

int main()
{
    Animal *aa = [Dog new];
    
    Dog *dd = (Dog *)aa;
    
    [dd run];
    
    return 0;
}


我们可以使用强制转换, 把Animal类型的aa强制转换为Dog类型, 并且输出~输出结果:

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> 父类类型的变量 不能 直接调用子类特有的方法。必须强转为子类类型变量后,才能直接调用子类特有的方法





好了, 这次我们就讲到这里, 下次我们继续~~~

原文地址:https://www.cnblogs.com/iOSCain/p/4282845.html