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.3 重载方法 - 图1

图 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方法。可行吗?为什么可行,或为什么不可行?