黑马程序员技术交流社区
标题:
OC中多态的全面解析(原创)
[打印本页]
作者:
叶子哥
时间:
2016-5-19 10:30
标题:
OC中多态的全面解析(原创)
/**
* 1.多态的理解
多态本是指事物的多种形态.(例如:水可以为液态水,固态冰,气态水蒸气)
代码中的体现为:父类的指针 指向了 子类的对象.
2.OC中多态的实现,前提是:
(1)类与类之间有继承关系.
(2)子类中有对父类中的方法进行了重写.
3.多态的好处:
如果函数或方法中的参数使用的是父类类型,则可以传入父类或者子类的对象,而不用定义多个函数或方法来匹配相应的类.
4.多态的局限性:
父类类型的变量不能直接调用子类中特有的方法.如果必须要调用,则必须先强制转换成子类,然后再近些调用.
说了这么多了,接下来进行具体的测试:
思路:
创建两个类(人类 和 学生类),具有继承关系,并且学生类新增了特有的属性和方法,并对人类中的一个方法进行了重写.
请先往下看,不着急看结论.
总结:
(1)OC语言是一门弱语法语言,在创建对象时,编译器在编译时并不能检测真实类型,只能在运行时才能动态检测对象类型.
(2)使用多态需要十分注意类与类之间的关系,子类本身所拥有的属性和方法就比父类多,并且子类拥有父类的所有属性和方法(包括重写的方法).
(3)不同类之间的对象转换问题:本质上不是真正的一个对象转变成另一个对象(逻辑上或情理上也是不可能的).这样的转换只是告诉编译器我们进行
了类型的转换,实际上指针所指向的那块内存空间一直都没有变化.
第一种情况:当把子类对象强制转换成父类对象时,只是把子类对象所拥有的特有属性和方法暂时屏蔽了.一旦把转换成的父类对象,再次转换成子
类对象时又可以访问子类对象所拥有的特有属性和方法.
第二种情况:当把父类对象强制转换成子类对象时,其实我们是对编译器进行欺骗操作.让编译器误认为转换成的子类对象,真的是一个子类对象,本
质上它还是个父类对象.所以编译时不会报错,一旦执行子类对象所拥有的特有属性和方法时,就会造成程序的崩溃.
*/
#import <Foundation/Foundation.h>
#import "YYPerson.h"
#import "YYStudent.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//1.直接创建一个父类对象
YYPerson *p1 = [YYPerson new];
[p1 eat];
[p1 sleep];
// [p1 study]; //父类对象不能调用子类中的方法
//2.直接创建一个子类对象
YYStudent *stu1 = [YYStudent new];
[stu1 eat]; //子类对象可以直接调用父类中的对象方法
[stu1 sleep]; //子类对象可以直接调用父类中的对象方法
[stu1 study];
//3.多态的实现
YYPerson *p2 = [YYStudent new]; //此时:父类的指针指向了子类的对象
[p2 eat]; //结果p2调用的是学生类中的 eat方法.
[p2 sleep]; //由于没有方法的重写,p2调用的仍然是人类中的 sleep方法
// [p2 study]; //父类类型的变量不能直接调用子类中特有的方法,不能通过编译.
YYStudent *stu2 = (YYStudent *)p2; //把父类的对象强制转换成子类的对象
[stu2 study]; //此时能调用子类中特有的方法 study方法
//4.子类对象 强制转换成 父类对象
YYStudent *stu3 = [YYStudent studentWithName:@"杰克" andAge:18 andNumber:@"5201314" andScore:100];
YYPerson *p3 = (YYPerson *)stu3;
[p3 eat]; //调用是学生中 eat方法
[p3 sleep]; //调用的是人类中的 sleep方法
// [p3 study]; //不能调用 --编译器直接报错
NSLog(@"stu3 address = %p",stu3); //stu3 address = 0x1005006a0
NSLog(@"p3 address = %p",p3); //p3 address = 0x1005006a0
/**
* 结论:OC中可以把子类对象强制转换成父类对象,其实这两个指针 指向了同一地址.并且转换成父类对象后,不能再调用子类中特有的属性和方法.
*/
//5.父类对象 强制转换成 子类对象
YYPerson *p4 = [YYPerson personWithName:@"汤姆" andAge:32];
YYStudent *stu4 = (YYStudent *)p4;
[stu4 eat]; //调用的是人类中的 eat方法
[stu4 sleep]; //调用的是人类中的 sleep方法
// [stu4 study]; //编译器不会报错,但是在执行时会崩溃,会告诉找不到 study方法.
/**
* 结论:OC中不可以把父类对象强制转换成子类对象,对编译器进行了欺骗操作,一旦访问了子类中特有的属性或者方法,就会导致程序崩溃.
*/
}
return 0;
}
复制代码
相关源代码Demo已上传至github
:[hide=d9999]https://github.com/yaomars/polymorphic[/hide]
作者:
1871037345
时间:
2016-5-19 12:04
好详细,收下了,呵呵
作者:
sincere126
时间:
2016-5-19 12:58
okok啦!这个好东东啦!
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2