——- android培训、IOS培训、期待与您交流! ———-
继承
使用继承可以定义一个具有父类所有功能的新类,即它继承了父类的功能。
以Circle 和 Rectangle 类为例:
@ubterface Circle : NSObject
{
@private
ShapeColcor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end // Circle
@interface Rectangle : NSObject
{
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end // Rectangle
这两个类接口除了名称,其他都是相同的。
再看两个类的实现:
@implementation Circle
- (void) setFillColor : (ShapeColor) c
{
fillColor = c;
} // setFillColor
- (void) setBound : (ShapeRect) b
{
bounds = b;
} // setBounds
@end // Circle
@implementation Rectangle
- (void) setFillColor : (ShapeColor) c
{
fillColor = c;
} // setFillColor
- (void) setBound : (ShapeRect) b
{
bounds = b;
} // setBounds
@end // Rectangle
这些方法具有完全一样的功能。不过draw
方法的名称和参数虽然一样,但是实现却不同。
@implementation Circle
- (void)draw
{
NSLog (@"drawing a circle at (%d %d %d %d) in %@",
bounds.x,
bounds.y,
bounds.width,
bounds.height,
colorName(fillColor);
);
} // draw
@end // Circle
@implementation rectangle
- (void)draw
{
NSLog (@"drawing rect at (%d %d %d %d) in %@",
bounds.x,
bounds.y,
bounds.width,
bounds.height,
colorName(fillColor);
);
} // draw
@end // Rectangle
将所有重复的内容合并在一起,还能在需要的地方拥有自定义的方法,这就是 继承 的特性。
下面创建一个新类Shape ,用于保存共有的实例和声明方法。Circle
类和Rectangle
类将从Shape
类继承而来。
@interface Shape : NSObject //冒号后面的标识符就是需要继承的类
{
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end // Shape
@implementation Shape
- (void) setFillColor : (ShapeColor) c
{
fillColor = c;
} // setFillColor
- (void) setBound : (ShapeRect) b
{
bounds = b;
} // setBounds
// 定义一个空的draw方法,以便Shape的子类通过他来实现各自的方法。
- (void) draw
{
} // draw
@end // Shape
Circle 类的接口和实现
@interface Circle : Shape
@end // Circle
@implementation Circle
- (void)draw
{
NSLog (@"drawing a circle at (%d %d %d %d) in %@",
bounds.x,
bounds.y,
bounds.width,
bounds.height,
colorName(fillColor);
);
} // draw
@end // Circle
Rectangle 类的接口和实现
@interface Rectangle : Shape
@end // Rectangle
@implementation Rectangle
- (void)draw
{
NSLog (@"drawing Rect at (%d %d %d %d) in %@",
bounds.x,
bounds.y,
bounds.width,
bounds.height,
colorName(fillColor);
);
} // draw
@end // Rectangle
代码精简了,功能相比之前没有任何变化。而且不需要更改main()
函数中设置和使用对象的任何代码。
调用继承的方法
当代码发送消息时,Objective-C 的方法调度机制将在当前的类中搜索相应的方法,如果无法在接收消息的对象的类文件中找到相应的方法,它就会在该对象的超类中进行查找。
对于类似[shape setFillColor : RedColor]
的代码,Objective -C 首先会寻找接收消息的对象,在这里就是Circle类的对象。该对象拥有一个指向Circle类的指针,Circle类也有一个指向其相应代码的指针。调用程序通过这些指针来查找正确的代码。如果Circle类中没有定义该方法,接下来它将在超类Shape中查找相应的方法。假如方法在Circle和Shape类中都没有找到,调用程序会继续在NSObjecr类中去寻找,因为它是继承链中的下一个超类。如果在最顶层的NSObject类中也没有找到该方法,则会出现一个运行时错误,同时出现一个编译时警告错误。
实例变量
创建新类时,对象首先从他的超类继承实例变量,然后根据自身情况添加新的实例变量。
比如一个新类RoundedRectangle
,这个类的接口定义如下:
@interface RoundedRectangle : Shape
{
@private
int radius;
}
@end // RoundedRectangle
NSObject类声明一个名为isa的实例变量,该变量保存一个指向对象当前类的指针。接下来是由Shape类声明的两个实例变量fillColor
和bounds
。最后是由RoundedRectangle声明的实例变量radius
。每个方法调用都获得一个名为self的隐藏参数。它是一个指向接收消息的对象的指针。这些方法通过self参数来寻找它们需要用到的实例变量。
方法重写
制作新类时,经常会添加自己的方法,或者替换某个超类定义的现有方法。Objective提供了super 关键字,让人既可以重写方法的实现,又能调用超类中的实现方式。
以Circle 类举例:
@implementaion Circle
- (void) setFillColor : (ShapeColor) c
{
if (c == RedColor) // 检查ShapeColor类的参数是不是红色
{
c = GreenColor; // 是,则改成绿色
}
[super setFillColor : c]; //请求超类响应消息
} // setFillColor
//Circle 类剩下的实现部分不变
当你向super发送消息时,实际上是在请求Objective-C向该类的超类发送消息。如果超类中没有地迎该消息,Objective-C继续在继承链的上一级中查找。