IOS多态特性

用一句话概括就是:事物在运行过程中存在不同的状态。先以教科书般举例说明,下文再举一个花木兰替父从军的例子帮助大家理解. 多态的存在有三个前提:
1.要有继承关系
2.子类要重写父类的方法
3.父类引用指向子类对,
但是其中又有很多细节需要注意。首先我们定义两个类,一个父类Animal,一个子类Cat。

父类Animal
@interface Animal : NSObject

- (void)eat;

- (void)run;

@end

@implementation Animal

- (void)eat;
{
    NSLog(@"动物在吃饭");
}
- (void)run;
{
    NSLog(@"动物在奔跑");
}

@end
子类Cat
@interface Cat : Animal

@property (nonatomic ,assign) NSInteger age;

- (void)catchMouse;

@end

@implementation Cat

- (void)eat
{
    NSLog(@"猫在吃饭");
}

- (void)run
{
    NSLog(@"猫在奔跑");
}

- (void)catchMouse
{
    NSLog(@"猫抓老鼠");
}

@end
测试
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    Animal *animal = [[Cat alloc] init];
    [animal eat];
    [animal run];
}

结果:
2018-10-22 11:00:58.816523+0800 Polymorphic[4372:1542859] 猫在吃饭
2018-10-22 11:00:58.816566+0800 Polymorphic[4372:1542859] 猫在奔跑

以上的三段代码充分体现了多态的三个前提,即:
1、存在继承关系
Cat类继承了Animal类
2、子类要重写父类的方法
子类重写(override)了父类的两个成员方法eat(),sleep()。其中eat()是非静态的,sleep()是静态的。
3、父类数据类型的引用指向子类对象。
测试类中Animal *animal = [[Cat alloc] init];语句在堆内存中开辟了子类(Cat)的对象,并把栈内存中的父类(Animal)的引用指向了这个Cat对象。
到此,满足了Java多态的的必要三个前提。

那么多态有什么弊端呢?有的,即多态后不能使用子类特有的属性和方法。往上面的代码看,子类Cat有一个特有的属性age; 并且还有一个特有的抓老鼠的方法- (void)catchMouse。但是在测试类中,我们尝试调用子类特有的方法- (void)catchMouse和打印子类特有的成员属性age; 就会报错。

[animal catchMouse];
animal.age  = 100;

原因就是多态的弊端,就是:不能使用子类特有的成员属性和子类特有的成员方法。

--------------------------------------------------华丽的分割线----------------------------------------------------------------------

如果在代码执行过程中还想使用Cat类中特有的属性age和它特有的成员方法- (void)catchMouse了怎么办呢?那我们就可以把这个父类引用指向了子类对象的家伙animal再强制变回Cat类型。这样animal就是Cat类型的引用了,指向的也是Cat对象了,自然也能使用Cat类的一切属性和一切的成员方法。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    Animal *animal = [[Cat alloc] init];
    [animal eat];
    [animal run];

    Cat *cat = (Cat *)animal;
    [cat catchMouse];
    cat.age = 100;
}

很明显,执行强转语句Cat *cat = (Cat *)animal;之后,ct就指向最开始在堆内存中创建的那个Cat类型的对象了。这就是多态的魅力吧,虽然它有缺点,但是它确实十分灵活,减少多余对象的创建,不用说为了使用子类的某个方法又去重新再堆内存中开辟一个新的子类对象

你可能感兴趣的:(IOS多态特性)