第9章 多态、动态类型和动态绑定
本章你将了解到Objective-C语言的一些特性。这些特性使它成为一门功能强大的编程语言,并且使其有别于其他面向对象的程序设计语言,如C++。本章中讲述了三个关键概念:多态、动态类型和动态绑定。多态使得能够开发以下程序:来自不同类的对象可以定义共享相同名称的方法。动态类型能使程序直到执行时才确定对象所属的类;动态绑定则能使程序直到执行时才确定要对对象调用的实际方法。
9.1 多态:相同的名称,不同的类
代码清单9-1显示了名为Complex的类的接口文件,它用于表示程序中的复数。
代码清单9-1接口文件Complex.h
//Interface file for Complex class
import<Foundation/Foundation.h>
@interface Complex:NSObject
{
double real;
double imaginary;
}
@property double real, imaginary;
-(void)print;
-(void)setReal:(double)a andImaginary:(double)b;
-(Complex)add:(Complex)f;
@end
你应该已经完成了第7章的练习6和练习7。我们在那个练习中加入一个补充的setReal:andImaginary:方法,使用它就可以用一条消息和合成存取器方法设置数字的实数和虚数部分,如下所示。
代码清单9-1实现文件Complex.m
//Implementation file for Complex class
import“Complex.h”
@implementation Complex
@synthesize real, imaginary;
-(void)print
{
NSLog(@“g+%gi”,real, imaginary);
}
-(void)setReal:(double)a andImaginary:(double)b
{
real=a;
imaginary=b;
}
-(Complex)add:(Complex)f
{
Complex*result=[[Complex alloc]init];
[result setReal:real+[f real]
andImaginary:imaginary+[f imaginary]];
return result;
}
@end
代码清单9-1测试程序main.m
//Shared Method Names:Polymorphism
import“Fraction.h”
import“Complex.h”
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
Fraction*f1=[[Fraction alloc]init];
Fraction*f2=[[Fraction alloc]init];
Fraction*fracResult;
Complex*c1=[[Complex alloc]init];
Complex*c2=[[Complex alloc]init];
Complex*compResult;
[f1 setTo:1 over:10];
[f2 setTo:2 over:15];
[c1 setReal:18.0 andImaginary:2.5];
[c2 setReal:-5.0 andImaginary:3.2];
//add and print 2 complex numbers
[c1 print];NSLog(@);[c2 print];
NSLog(@“————”);
compResult=[c1 add:c2];
[compResult print];
NSLog(@“n”);
[c1 release];
[c2 release];
[compResult release];
//add and print 2 fractions
[f1 print];NSLog(@);[f2 print];
NSLog(@“—-”);
fracResult=[f1 add:f2];
[fracResult print];
[f1 release];
[f2 release];
[fracResult release];
[pool drain];
return 0;
}
代码清单9-1输出
18+2.5i
+
-5+3.2i
13+5.7i
1/10
+
2/15
7/30
注意,Fraction和Complex类都包含add:和print方法。所以,当执行以下消息表达式
compResult=[c1 add:c2];
[compResult print];
时,系统如何知道执行哪个方法呢?其实很简单:Objective-C运行时知道第一条消息的接收者c1是一个Complex对象。因此,选择定义在Complex类中的add:方法。
Objective-C的运行时系统还确定compResult是一个Complex的对象。因而,它选择定义在complex类中的print方法来显示加法的结果。同样的论述也适用于以下消息表达式:
fracResult=[f1 add:f2];
[fracResult print];
注意第13章将更加详尽描述,系统总是携带有关“一个对象属于哪个类”这样的信息。这信息能使系统在运行时而不是在编译时做出这些关键性的决定。
选择Fraction类中相应的方法来计算基于f1和fracResult类的消息表达式。
前面提到过,使不同的类共享相同方法名称的能力称为多态。它能使你开发一组类,这组类中的每一个类都能响应相同的方法名。每个类的定义都封装了响应特定方法所需的代码,这就使得它独立于其他的类定义。多态还允许你后来添加新类,这些新类能响应相同的方法名。
注意在结束本节之前,注意Fraction类和Complex类应该负责释放它们add:方法而不是测试程序生成的结果。事实上,这些对象应该被自动释放。我们将在第17章对此进行更加详细的讨论。