为C++编程者开发的Objective-C(一)

www.informit.com

David Chisnall

20081121

 

David ChisnallObjective-C打交道已经很多年了,他既是一个使用者也是一个编译器作者。 在下面的三部分系列里,他给出了这种语言的一个引导介绍。 第一部分介绍了这种语言的历史和基本原理。

 

老读者都知道我这些天花了很长时间写Objective-C的代码。现在我已经完成一个Smalltalk的编译器,这个编译器可以在对象与Objective-C的对象相关联的地方产生代码。同时,这篇文章也可以给那些熟悉C++的人一个关于Objective-C大概的介绍。

 

Objective-C是为C提供给类Smalltalk语义学的最小集合的拓展而设计的。它也包括了类Smalltalk的语法,这可以轻松的看出部分代码是纯C的,并且这部分包括Objective-C的拓展。

 

C++不同,Objective-CC的一个超集。每一个C程序都是一个有效的Objective-C程序。所有Objective-C中新关键字都以@未前缀,但在C的标识符这并不是有效的。

 

运行时系统

Objective-C的第一个具体实现是一个预处理器,它使Objective-C转化为C。语言的动态特性由一个运行时库提供。现代的编译器不用C作为中间语言, 但他们对运行时库提供动态特性有着相同的约定。

 

Objective-C,对象都是C结构体,只是这些结构体第一个元素是一个指向另一个用来代表类的C结构体。准确的来说在运行时这个类结构有些变化,但至少包含查找方法的信息要求、实例变量的布局和其他一些元数据。

 

因为Objective-CC的超集,并且运行时库的所有特性(包括类结构)C是公开的, 这就意味着Objective-C对编程人员完全公开对象模型。这在Objective-C并不奇怪。当你在C++调用一个方法时,编译器通过虚表进行一些复杂操作来找到正确的代码运行。在Objective-C,如下:

 

调用一个C函数来查找实现方法的函数(通过GNU运行时)

调用一个查找方法的C函数并且在一次运算中调用(通过Apple运行时)

这就意味着你可以编写纯C代码与Objective-C对象交互。它也允许你在你需要的情况下绕过一些动态行为。

 

一些历史

19世纪80年代初,Objective-CBrad Cox发明,起初是作为对C微小集合的拓展来支持Smalltalk风格的对象。它从面向对象预编译项目中脱颖而出,这个项目与Objective-C有着相似的语义但的确是些复杂的语义。

 

最初的实现和Objective-C的商标由NeXT持有并全部应用在新的操作系统中。NeXTObjective-C中创建了一个GUI工具集和一个接口创建器。这被广泛认为第一个商业快速应用开发(RAD)工具。好的一面就是接口创建器并不保存接口描述存储序列化对象。这种方式可以保持一个模式-视图-控制器清楚的分离并且以可装载模式存储控制器和视图。

 

早在19世纪90年代,NeXTSunNeXT环境分别构建了便携版本。而NeXT初始系统在一些地方使用了纯C语言,新版本定义了两个框架:FoundationAppKitFoundation定义了核心功能,包括集合类,字符串和其他一些东西。AppKit包含了GUI框架。这两个都定义在OpenStep规格说明中,而这个说明也在NeXTSun和随后的一些GNU项目中实施。在收购NeXT之后,苹果公司将OpenStep实施改名为”Cocoa”。因为OpenStep基于早期的NeXT设计,在OpenStep的所有的类都以NS为前缀。

 

GCC支持Objective-C的历史颇有些趣味性色彩。起初的实现是由NeXT所编写,而保存在一个分离的库,这样使用者可以链接他们的GCC的版本。通过没有和GCC的分离,NeXT希望规避GPL。这个小把戏没有成功,而且NeXT最后被要求公开源代码。然而,并没有要求公开运行时库的源代码,这就意味着编译器在其他平台都没有作用。Richard Stallman 编写了一个新的版本实际上是用来取代NeXT运行时。这后来被更新的版本取代。

 

GCC中,Objective-C现在的代码基于你使用的学科。NeXT保留着自己的版本,这个版本因为没有分层而且都在单一源文件中所以仅仅勉强维持, 并且只支持NeXT运行时。GCC包含了一个不用维护的,基于NeXT代码但以#ifdefs标记的GNU运行时。

 

曾经GCC支持Objective-C并试图以复制NeXT环境开始。GNUstep项目最终从这里发展并且实施几乎所有的OpenStepCocoa附加的一些。它也包括NeXT的接口创建器的取代:GNU对象关系模型(GORM)

 

一些语法

Objective-C中语法的加法被设计为强调各种面向对象代码的语义。在C++中,你可以这样做:

 

doSomething();这是调用一个C函数,调用一个静态的C++成员函数通过现前的对象传递作为一个隐含的参数,或者调用一个可以在子类中实现虚函数, 通过现前的对象作为一个隐含的参数。换一种方法,你也可以这样做:

 

a.doSomething();这是调用一个C函数指针,它是一个结构体的域,调用一个定义在类上的静态成员函数其中你认为a是类的一个实例,或者一个定义在类上的虚方法其中a是一个真正实例。

 

相反,在Objective-C中看起来象C其实就是C。在Objective-C中调用一个方法的等价源于Smalltalk语法:

 

[a doSomething];方括号用来包装类Smalltalk信息发送语法。我将回过头来讲诉发送消息和调用函数的区别。当你有一个有很多参数的方法时,这些参数在Objective-C都有自己的名字,象这样:

 

[aDictionary setObject:@”a string” forKey:@”a key”];对那些熟悉C语法的人这看起来非常奇怪,但它意味着你花很少时间去考虑参数的顺序。而且如果你先前不知道aDictionary是类的一个实例的话这也使代码易读—你知道这种方法传递一个对象和一个键,而且你只知道这些。

 

在后台,这转化为下面这些:

SEL sel = sel_get_uid(“setObject:forKey:”)

IMP method = obj_msg_lookup(aDictionary->isa,sel)

method(aDictionary, sel, @”a string”, @”a key”);我将回过头来讲诉sel是什么。当这起作用时,这并没有象发生的那样—当模块加载的时候通过运行时库的初始化填充sel的值。NeXT/Apple将后面两步合二为一如下:

 

obj_msgSent(aDictionary, sel, @”a string”, @”a key”);速度稍微快些,但使实现优化类似不确定性内联变得稍微困难一些。因为这些是C函数,他们也不特殊——你可以在你自己的代码中调用他们。有一件有趣的事情,在LLVMC语言家族前后树是一个复写者,它包含Objective-C源文件并编译成C源文件以兼容在NeXT运行时库。

 

对象模型

术语面向对象是由Alan Kay19世纪60年代提出的。他一直和一个在Xerox PARC的小组从事开发Smalltalk语言,并且这种语言作为编程模型思想的具体体现。

 

面向对象编程最基础的想法是通过简单的计算机模型来传递消息。这非常有别于C++方式,C++有点类似面向对象,但它基于函数和数据结构结合的思想。

 

C++中,对象是一系列与函数有关的结构,而这些函数或是静态的或是虚的。一个静态函数语义上等价于一个C函数,这个函数隐含的第一个参数包含着对象。这完全是对C的无指针拓展,因为下面两个是相等的。

 

//C++

object->function();

 

//C

function(object)C++版本更多的作为代表,但并没有任何语义上区别。

 

C++在虚成员函数的格式上也支持一些变通。在先前的例子里如果函数是个虚函数,真正的函数调用取决于对象的类。如果它是静态的,调用函数取决于调用者所考虑类的对象。

 

Objective-C,没有等价于静态成员函数。如果你想要这个功能, 你只能使用C函数。Objective-C中的方法与C++中的虚方法非常相似,但有一些重要的区别。首先是语法不同:

 

[object message];发送命名消息到对象。执行代码作为这个行为的结果,而这完全取决于对象的类。这一点非常不同于C++的等价:在C++中,这种机制稍微取决于所考虑类的对象。

 

假设你有一个类继承于四个类。A是父类,BCA的子类,DB的子类。在C++中,除了A其他的类都实现虚函数doSomething(),你可以称这种方式叫模板。考虑下面:

 

object.doSomething()如果你认为对象是类BD的,并且实际上是类D的对象。实现声明通过D被调用。如果你认为是类C的,将通过C的实现来调用。如果你认为是A的一个实例,你需要尝试两个显式动态映射并且看看哪一个起作用,或是否使用同一个模板。

 

如果你在Objective-C中有相同的类约定,用BCD实现一个doSomething方法,你可以尝试如下:

 

[object doSomething];如果你认为对象是B类型的,但其实是C类型的,doSomething方法依然会被调用。如果你认为是类A的实例,编译时警告弹出,A的实例没有回应一个doSomething消息。如果真的是BC或是D的实例,它将在运行时起作用,但它是A的一个实例,运行时异常将会弹出。

 

多继承在Objective-C中没有实现,但相对于C++来说远远没必要。在C++中,方法的查找基于继承链,所以你无法使用两个类继承,除非他们有共同的父类。在Objective-C中,你可以完全使用两个类在回应相同消息的条件下进行交互。

 

总结

我们已经浏览了Objective-C的历史和语言背后的核心思想。我们也发现了一些语言的重要部分:给对象发消息。在第二部分,我们会看到更多的核心语法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值