OC语法之多态

来源:互联网 发布:淘宝店铺买卖 安全吗 编辑:程序博客网 时间:2024/05/16 00:31

OC指针类型的变量有两个:一个是编译时类型,一个是运行时类型,编译时的类型由声明该变量时使用的类型决定,运行时的类型有实际赋给该变量的对象决定.如果编译类型和运行类型不一致,就可能出现多态.

下面直接上代码:

一:多态性

#import <Foundation/Foundation.h>//定义一个基本类型@interface SHBase : NSObject-(void)base;-(void)test;@end#import "SHBase.h"@implementation SHBase- (void) base{    NSLog(@"父类的普通base方法");}- (void) test{    NSLog(@"父类的将被覆盖的test方法");}@end#import "SHBase.h"//定义一个子类@interface SHSubclass : SHBase-(void)sub;@end#import "SHSubclass.h"@implementation SHSubclass//重写父类的test方法- (void) test{    NSLog(@"子类的覆盖父类的test方法");}- (void) sub{    NSLog(@"子类的sub方法");}@end/** *   多态性 */-(void)testOne{    // 下面编译时类型和运行时类型完全一样,因此不存在多态    SHBase *base = [[SHBase alloc] init];    // 下面两次调用将执行BaseClass的方法    [base base];    [base test];    // 下面编译时类型和运行时类型完全一样,因此不存在多态    SHSubclass* subclass = [[SHSubclass alloc] init];    // 下面调用将执行从父类继承到的base方法    [subclass base];    // 下面调用将执行子类重写的test方法    [subclass test];    // 下面调用将执行子类定义的sub方法    [subclass sub];    // 下面编译时类型和运行时类型不一样,多态发生,编译的时候是SHBase类型,运行时是SHSubclass类型.    // 因为子类其实是一种特殊的父类,因此 OC 允许把一个子类对象直接赋值给一个父类指针变量,无需任何类型装换.    // 注意了:调用的时候方法行为总是表现子类方法的行为特征,而不是父类的方法.这里就是:相同类型的变量调用同一个方法    // 时呈现多种不同的行为特征,那就是多态.    SHBase* ploymophicBc = [[SHSubclass alloc] init];    // 下面调用将执行从父类继承到的base方法    [ploymophicBc base];    // 下面调用将执行子类重写的test方法    [ploymophicBc test];    // 因为ploymophicBc的编译类型是FKBase    // FKBase类没有提供sub方法,所以下面代码编译时会出现错误。    // [ploymophicBc sub];    // 可将任何类型的指针变量赋值给id类型的变量,为了解决编译类型的检査问题,可以使用 id类型,    // 程序可以对任何对象或者任何类型的指针变量赋值为 id 类型的变量,而且使用 id 类型可以调用    // 该变量实际所指对象的方法.    id dyna = ploymophicBc;    [dyna sub];//    2016-01-08 18:50:13.091 OC 多态[4748:2315316] 父类的普通base方法//    2016-01-08 18:50:13.092 OC 多态[4748:2315316] 父类的将被覆盖的test方法//    2016-01-08 18:50:13.092 OC 多态[4748:2315316] 父类的普通base方法//    2016-01-08 18:50:13.092 OC 多态[4748:2315316] 子类的覆盖父类的test方法//    2016-01-08 18:50:13.092 OC 多态[4748:2315316] 子类的sub方法//    2016-01-08 18:50:13.092 OC 多态[4748:2315316] 父类的普通base方法//    2016-01-08 18:50:13.092 OC 多态[4748:2315316] 子类的覆盖父类的test方法//    2016-01-08 18:50:13.092 OC 多态[4748:2315316] 子类的sub方法}

二:指针变量的强制类型转换

/** *  指针变量的强制类型转换 */-(void)testTwo{    /*      注意:强制类型转换只是改变了该指针变量的编译类型,但是该变量所指向对象的实际          类型并不会发生改变,如果程序不断进行转换,转换出来的变量在调用方法时就会引发错误.     */    // 声明hello时使用NSObject类,则hello的编译时类型是NSObject,    // NSObject是所有类的父类 , 但hello变量的实际类型是NSString    NSObject *obj = @"Hello";    // 由于obj变量所指向的对象是NSString对象,所以运行时也可通过    NSString* objStr = (NSString*)obj;    NSLog(@"%@" , objStr);    // 定义一个obj2变量,编译类型为NSObject,实际类型为NSString    NSObject* obj2 = @"iOS";    // 尝试将obj2强转为NSDate,这行代码没有任何问题    // 但程序只是定义一个NSDate类型的指针,该指针与obj2指向同一个对象    NSDate* date = (NSDate*)obj2;    // 程序调用date的isEqualToDate:方法。    // 由于date的编译时类型是NSDate,因此编译时没有任何问题    // 由于date实际指向的对象是NSString,因此程序执行时就会引发错误,    NSLog(@"%d" , [date isEqualToDate:[NSDate date]]);    /*     程序奔溃:     *** Terminating app due to uncaught exception 'NSInvalidArgumentException',      reason: '-[__NSCFConstantString isEqualToDate:]: unrecognized selector sent to instance 0x5054     字符串并没有isEqualToDate方法.     */}

三:判断指针变量的实际类型

/** *   判断指针变量的实际类型 */-(void)testThree{    /*       注意:为了保证程序能够正常运行,一般建议在执行强转之前先判断该对象是否为该类,或者其子类.判断指针变量实际指向的对象是否为某个类,某个子类,可以使用如下方法:     - (BOOL)isKindOfClass:(Class)aClass; 判断对象是否为aClass类     - (BOOL)isMemberOfClass:(Class)aClass; 判断对象是否为aClass类的实例.     */    NSObject* hello = @"Hello";    // 使用isKindOfClass判断该变量所指的对象是否为指定类、及其子类的实例    NSLog(@"字符串是否是NSObject类的实例:%d"          , ([hello isKindOfClass:[NSObject class]]));    // 返回true。    NSLog(@"字符串是否是NSString类的实例:%d"          , ([hello isKindOfClass:[NSString class]]));    // 返回false。    NSLog(@"字符串是否是NSDate类的实例:%d"          , ([hello isKindOfClass:[NSDate class]]));    NSString* a = @"Hello";    // 返回false    NSLog(@"a是否是NSDate类的实例:%d"          , ([a isKindOfClass:[NSDate class]]));}
0 0
原创粉丝点击