8.3 重载方法
前面一节提到过,不能通过继承删除或减少方法。但可以利用重载来更改继承方法的定义。
回头看这两个类:ClassA与ClassB。假定要为ClassB编写自己的initVar方法。你已经知道ClassB将继承定义在ClassA中的initVar方法,但是否可以新建一个同名的方法来替代继承的方法呢?答案是可以,只要定义一个同名的新方法即可。使用和父类相同的名称定义的方法代替或重载了继承的定义。新方法必须具有相同的返回类型,并且参数的数目与重载的方法相同。
代码清单8-6展示了简单的例子来说明这个概念。
代码清单8-6
//Overriding Methods
import<Foundation/Foundation.h>
//ClassA declaration and definition
@interface ClassA:NSObject
{
int x;
}
-(void)initVar;
@end
@implementation ClassA
-(void)initVar
{
x=100;
}
@end
//ClassB declaration and definition
@interface ClassB:ClassA
-(void)initVar;
-(void)printVar;
@end
@implementation ClassB
-(void)initVar//added method
{
x=200;
}
-(void)printVar
{
NSLog(@“x=%i”,x);
}
@end
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]]int];
ClassB*b=[[ClassB alloc]init];
[b initVar];//uses overriding method in B
[b printVar];//reveal value of x;
[b release];
[pool drain];
return 0;
}
代码清单8-6输出
x=200
显然消息
[b initVar];
导致使用定义在ClassB中的initVar方法,而不是使用ClassA中所定义的方法,前一示例也是如此。如图8-9所示。
图 8-9 重载initVar方法
8.3.1 择哪个方法
前面曾讲到系统如何上溯类层次查找应用于对象的方法。如果在不同的类中有名称相同的方法,则根据作为消息的接收者的类选择正确的方法。代码清单8-7使用与前面的ClassA和ClassB相同的类定义。
代码清单8-7
import<Foundation/Foundation.h>
//insert definitions for ClassA and ClassB here
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
ClassA*a=[[ClassA alloc]init];
ClassB*b=[[ClassB alloc]init];
[a initVar];//uses ClassA method
[a printVar];//reveal value of x;
[b initVar];//use overriding ClassB method
[b printVar];//reveal value of x;
[a release];
[b release];
[pool drain];
return 0;
}
编译该程序时会得到以下警告消息:
warning:‘ClassA’may not respond to‘-printVar’
这里有什么问题?前一节讨论过此问题。观察ClassA的声明:
//ClassA declaration and definition
@interface ClassA:NSObject
{
int x;
}
-(void)initVar;
@end
注意没有声明printVar方法。该方法声明并定义在ClassB中。因此,尽管ClassB对象及其派生类可以通过继承使用此方法,但是ClassA对象却不能使用此方法,这是由于此方法是沿着类层次定义的。
注意你可以通过某种方式强制使用此方法,但是我们这里不对此进行讨论,此外,这也不是一个好的编程实践。
回到例子,为ClassA添加一个printVar方法,以便显示实例变量的值:
//ClassA declaration and definition
@interface ClassA:NSObject
{
int x;
}
-(void)initVar;
-(void)printVar;
@end
@implementation ClassA
-(void)initVar
{
x=100;
}
-(void)printVar
{
NSLog(@“x=%i”,x);
}
@end
ClassB的声明与定义保持不变。现在,再次尝试编译并运行该程序。
代码清单8-7输出结果
x=100
x=200
现在可以讨论这个实际例子。首先,分别将a和b定义为ClassA及ClassB对象。经过内存分配与初始化后,向a发送一条消息,让它应用initVar方法。此方法在ClassA中定义,所以,它是所选的方法。此方法只是将实例变量值设为100然后返回。然后调用刚刚添加到ClassA中的printVar方法来显示的x值。
ClassB对象b类似,经过内存分配及初始化后,将实例变量x设为200,最后显示其值。
一定理解如何按照a与b所属的类选择相应的方法。这是Objective-C中面向对象编程的基础概念。
作为练习,考虑从ClassB中删除printVar方法。可行吗?为什么可行,或为什么不可行?