理解Objective-C多态

多态性

OC的指针类型的变量有俩个:一个是编译时的类型,一个是运行时的类型,编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型完全不一致,就可能出现所谓的多态——来自疯狂iOS讲义

#import <Foundation/Foundation.h>
@interface FKBase: NSObject
- (void) base;
- (void) test;
@end

下面定义一个类来继承上面的类?

#import <Foundation/Foundation.h>
#import "FKBase.h"
@interface FKSubclass : FKBase
- (void) sub;
@end

第一个类的实现部分⬇️

#import "FKBase.h"
@implementation FKBase
- (void) base {
    NSLog(@"普通方法");
}
- (void) test {
    NSLog(@"父类的将被覆盖的test方法");
}
@end

第二个类的实现部分⬇️

#import <Foundation/Foundation.h>
#import "FKSubclass.h"
@implementation FKSubclass
- (void) test {
    NSLog(@"子类覆盖父类的test的方法");
}
- (void) sub {
    NSLog(@"子类的sub方法");
}
@end
int main(int argc, char * argv[]) {
    @autoreleasepool {
        FKBase * bc = [[FKBase alloc] init];
        [bc base];
        [bc test];
    // 下面编译时e类型和运行时类型完全一样,因此不存在多态
        FKSubclass * sc = [[FKSubclass alloc] init];
    // 下面调用将执行从父类继承到的base方法
        [sc base];
    // 下面调用将执行子类重写的test方法
        [sc test];
    // 下面调用将执行子类定义的sub方法
        [sc sub];
    // 下面编译时类型和运行时类型不一样,发生多态
        FKBase * sb = [[FKSubclass alloc] init];
    // 下面调用从FKBase继承得到的base方法
        [sb base];
    // 下面将调用执行子类重写的test方法
        [sb test];
    // 因为sb的编译类型时FKBase
    // FKBase类没有提供sub方法,所以[sb sub]会报错
    //可以将任何类型的指针变量赋值给id类型
        id sb2 = sb;
        [sb2 sub];
    }
}

以上前一部分定义的指针变量与创建的对象类型一致(bc和sc),第三个指针变量sb,编译时类型为FKBase,而运行时却是FKSubclass,当调用test方法时,执行了FKSubclass里重写的test方法。

  • 子类是特殊的父类,OC允许把一个子类对象直接赋给一个父类的指针变量,无需类型转换。
  • 当一个子类对象直接赋给父类指针时,例如FKBase * sb = [[FKSubclass alloc]init];这个sb变量在编译时类型还是FKBase,在运行时变成了FKSubclass,当运行时调用该指针变量的方法时,其方法总是表现子类方法也就是调用子类方法,这就可能出现相同类型的变量调用同一个方法出现不同的行为特征,这就时多态
  • 指针变量在编译阶段指针调用其编译类型所具有的方法,但运行时则执行运行时类型所具有的方法

指针变量的强制类型转换

  1. 类型转换运算符是圆括号(),用法:
    (type *)variable
    将variable转换成一个type类型的变量
    2.这种强制转换只是改变了指针变量的编译时类型,但是该变量所指对象的实际类型不会发生改变
#import <Foundation/Foundation.h>
#import "FKSubclass.h"
int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSObject * obj = @"Hello";
        //由于objd变量所指的对象是NSString对象,所以运行时也可以通过。
        NSString * objStr = (NSString *)obj;
        NSLog(@"%@", objStr);
        //  定义一个obj2变量,编译类型为NSObject,实际类型为NSString
        NSObject * obj2 = @"iOS";
        //尝试将obj2强制转换为NSDate,这行代码没有问题
        //但程序只是定义了一个NSDate类型的指针,该指针与obj2指向同一个对象
        NSData * date = (NSData *) obj2;
        // 程序调用date的isEqualToDate:方法
        //由于date的编译类型是NSDate,因此编译时没有任何问题
        //由于date实际指向的对象时NSString,因此程序执行时就会引发错误
        NSLog(@"%d", [date isEqualToDate:[NSDate date]]);
    }
}

当把子类赋给父类对象时,被称为向上转型,这种转型总是可以成功的,这也从另一个侧面证实了子类是一种特殊的父类。这种转型只是表明这个指针变量的编译类型是父类,但实际执行它的方法时,依然子类对象的行为方式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值