郝萌主倾心贡献,尊重作者的劳动成果,请勿转载。
如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^
我要捐赠: 点击捐赠
Cocos2d-X×××:点我传送
多态能够使来自不同类的对象定义相同名称的方法。
动态类型能使程序直到执行时才确定对象所属的类。
动态绑定则能使程序直到执行时才确定实际要调用的对象方法。
简单点说:相同的名称,不同的类,系统总是携带有关“一个对象属于哪个类”这样的信息。
该信息能使系统在运行时做出这些关键性的决定,而不是在编译时。
这种使不同的类共享相同方法名称的能力就称为多态。
Graphics(几何图形) 类是Ellipse(椭圆形) 类和Triangle(三角形) 类的父类,
个onDraw, 这是因为在几何图形中是无法知道要绘制的是椭
圆形和三角形, 这个方法应该是类似Java中的抽象方法, 或者是
C++中的虚方法。
@interface Graphics : NSObject {
}
-(void) onDraw;
@end
#import <Foundation/Foundation.h> #import "Graphics.h" @interface Ellipse : Graphics { } @end
#import "Ellipse.h" @implementation Ellipse -(void)onDraw { NSLog(@"绘制椭圆形"); } @end
#import <Foundation/Foundation.h> #import "Graphics.h" @interface Triangle : Graphics { } @end
#import "Triangle.h" @implementation Triangle -(void)onDraw { NSLog(@"绘制三角形"); } @end
#import <Foundation/Foundation.h> #import "Graphics.h" #import "Ellipse.h" #import "Triangle.h" int main (int argc, const char * argv[]) { Graphics *graphics; graphics = [[Ellipse alloc] init]; [graphics onDraw]; [graphics release]; graphics = [[Triangle alloc] init]; [graphics onDraw]; [graphics release]; return 0; }运行结果:
绘制椭圆形
id graphics;
graphics = [[Ellipse alloc] init];
[graphics onDraw];
[graphics release];
graphics = [[Triangle alloc] init];
[graphics onDraw];
[graphics release];
return 0;
}
由于动态类型的关系,id 在执行时,
务必注意,声明中并没有使用星号。
#import <Foundation/Foundation.h> @interface Vector : NSObject { double vec1; double vec2; } @property double vec1,vec2; -(void)print; -(void)setVec1:(double)v1 andVec2:(double) v2; -(Vector *)add:(Vector *)v; @end
#import "Vector.h" @implementation Vector @synthesize vec1,vec2; -(void) setVec1:(double) v1 andVec2:(double)v2 { vec1 = v1; vec2 = v2; } -(Vector *)add:(Vector *)v { Vector *result = [[Vector alloc] init]; [result setVec1:vec1 + [v vec1] andVec2: vec2 + [v vec2]]; return result; } -(void)print { NSLog(@"%g, %g",vec1,vec2); } @end
#import <Foundation/Foundation.h> @interface Scalar : NSObject { double scal; } @property double scal; -(void)print; -(void)setScal:(double)sval; -(Scalar *)add:(Scalar *)s; @end
#import "Scalar.h" @implementation Scalar @synthesize scal; -(void)print { NSLog(@"%g", scal); } -(void)setScal:(double)sval { scal = sval; } -(Scalar *)add:(Scalar *)s { Scalar *result = [[Scalar alloc] init]; [result setScal:scal + [s scal]]; return result; }
#import <Foundation/Foundation.h> #import "Vector.h" #import "Scalar.h" int main (int argc, const char * argv[]) { Scalar *scA =[[Scalar alloc] init]; Scalar *scB =[[Scalar alloc] init]; Vector *vecA =[[Vector alloc] init]; Vector *vecB =[[Vector alloc] init]; id scAandB; id vecAandB; [scA setScal: 10.5]; [scB setScal: 13.1]; [vecA setVec1: 3.2 andVec2: 4.7]; [vecB setVec1: 32.2 andVec2: 47.7]; [vecA print]; NSLog(@" + "); [vecB print]; NSLog(@" = "); vecAandB = [vecA add: vecB]; [vecAandB print]; [scA print]; NSLog(@" + "); [scB print]; NSLog(@" = "); scAandB = [scA add: scB]; [scAandB print]; [scA release]; [scB release]; [scAandB release]; [vecA release]; [vecB release]; [vecAandB release]; return 0; }
+
32.2, 47.7
=
35.4, 52.4
10.5
+
13.1
=
23.6
注意:
为什么要使用静态类型:
1)将一个变量定义为特定类的对象时,使用的是静态类型。
“静态”指的是对存储在变量中对象的类型进行显示声明。
这样存储在这种形态中的对象的类是预定义的,也就是静态的。
使用静态类型时,编译尽可能确保变量的用法在程序中始终保持一致。
编译器能够通过检查来确定应用于对象的方法是由该类定义的还是由该类继承的,否则它将显示警告信息。
也就是说“静态类型” 在编译阶段检查错误, 而不是在执行阶段。
2)使用静态类型的另一个原因是程序可读性好。。
动态类型的参数和返回类型:
如何使用动态类型来调用一个方法,需要注意如下规则:
如果在多个类中实现名称相同的方法,那么每个方法都必须符合各个参数的类型和返回值类型。
这样编译器才能为消息表达式生成正确的代码。编译器会对它所遇到的每个类声明执行一致性检查。
当一个方法选取对象作为它的参数,而另一个方法选取浮点数作为参数时,
或者一个方法以对象作为返回值,而另一个以整型数作为返回值。
编译器可能生成不正确的代码来向方法传递参数或处理返回值。
处理动态类型的方法:
-(BOOL) isKindOf:class-object(判断对象是否是class-object或其子类的成员) -(BOOL) isMenberOfClass:class-object(判断对象是否是class-object的成员) -(BOOL) respondsToSelector:selector(判断对象是否能够响应selector所指定的方法) +(BOOL) instancesRespondToSelector:selector(判断指定的类实例是否能响应selector所指定的方法) +(BOOL) isSubclassOfClass:class-object(判断对象是否是指定类的子类) -(id) performSelector:selector(应用selector指定的方法) -(id) performSelector:selector withObject:object(应用selector指定的方法,传递参数object) -(id) performSelector:selector withObject:object1 withObject:object2(应用selector指定的方法,传递参数object1和object2可以对一个方法名应用@selector指令。
例如:@selector (alloc)为名为alloc的方法生成一个SEL类型的值,该方法是从NSObject类继承的。
记住,测试包含继承的方法,并不是只测试直接定义在类中的方法。
performSelector:方法和它的变体允许你向对象发送消息,这个消息可以是存储在变量中的selector。
在iOS中,respondsToSelector:方法广泛用于实现委托(delegation)的概念。
为了让系统能够检查你确实实现了特定的方法,
使用respondsToSelector:判断是否可以将事件的处理委托给你的方法。
如果你没有实现这个方法,它会自己处理该事件,按定义的默认行为来执行。
使用@try处理异常
@try:如果块中的某一语句抛出异常,执行不会终止,而是立即跳到@catch块继续执行
@catch:处理异常,可行的执行顺序是记录出错信息,清除和终止执行。
@finally:使用@finally块包含是否执行抛出异常的@try块中的语句代码;
@throw:允许你抛出自己的异常,
这些概念和java的或者其它语言差不多。
一般来说,需要考虑更好的编程实践,
应该在错误发生前做系统的全面的覆盖性测试,而不是在错误发生后捕获异常。
抛出异常会使用大量的系统资源,Apple反对非必要的使用异常。
请发表评论