上一章Objective-C开发教程请查看:Objective-C协议(Protocol)用法解析
众所周知,多态就是父类的指针指向子类的对象,那么这是如何做到的呢?这是OC的运行时runtime使程序在运行时才确定对象的类型,以及实际调用的方法,因此,这又叫做动态类型。
动态类型识别是通过isa指针实现的,运行时根据对象的isa指针寻找实际的类型,找到对应的属性或方法。
Objective-C的代码会被翻译成C的代码运行,其实也就是说类的所有信息(属性和方法)都会转成C相应的形式,在C层对OC的类结构进行控制可以得到所谓的动态特性,因而动态特性是因为编译器的存在,而动态类型是在运行时进行类型检查的。
OC中一个对象调用指定的方法不是由编译器决定,而是由运行时决定的,这又叫做动态绑定。相反类型在编译的时候进行检查的,又称为静态类型检查,显式使用指定类型的都会有静态类型检查,如int等。
动态绑定和id类型
一般的动态绑定实现使用id类型进行声明,id类型是一个类似void*的指针,也就是泛型,它的好处就是可以容纳任何类型的指针。
使用id类型声明的对象,编译器不会对其进行类型检查,只有在运行时才检查,并决定实际调用。不过即使如此,建议尽量少用,因为这样的代码很不清晰。
下面是一个动态绑定的例子:
#import <Foundation/Foundation.h>
@interface Square:NSObject {
float area;
}
- (void)calculateAreaOfSide:(CGFloat)side;
- (void)printArea;
@end
@implementation Square
- (void)calculateAreaOfSide:(CGFloat)side {
area = side * side;
}
- (void)printArea {
NSLog(@"正方形面积: %f",area);
}
@end
@interface Rectangle:NSObject {
float area;
}
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth;
- (void)printArea;
@end
@implementation Rectangle
- (void)calculateAreaOfLength:(CGFloat)length andBreadth:(CGFloat)breadth {
area = length * breadth;
}
- (void)printArea {
NSLog(@"长方形 %f",area);
}
@end
int main() {
Square *square = [[Square alloc]init];
[square calculateAreaOfSide:10.0];
Rectangle *rectangle = [[Rectangle alloc]init];
[rectangle calculateAreaOfLength:10.0 andBreadth:5.0];
NSArray *shapes = [[NSArray alloc]initWithObjects: square, rectangle,nil];
id object1 = [shapes objectAtIndex:0]; // 动态绑定
[object1 printArea];
id object2 = [shapes objectAtIndex:1]; // 动态绑定
[object2 printArea];
return 0;
}
类的前置声明
我们可以通过使用编译指令@class告诉编译器某个符号是一个类名,这种写法称为类的前置声明。多个类使用逗号隔开,以分号结束,前置声明也可以声明多次,如下例子:
@class NSString,NSArry,NSMutableArry;
@class Volume;
但是要注意,@class仅仅是告诉编译器符号是类名,这可以提高编译速度,但是使用到类的属性和方法,则需要导入头文件。
类的前置声明的主要使用是:累互相嵌套包含的时候,可以使用类的前置声明解决。
评论前必须登录!
注册