C++ | Objective-C |
在 C++ 中,一个类可以继承自一个或多个类,使用 public、protected 以及 private 修饰符。子类的函数如果要调用父类的版本,需要使用 :: 运算符,例如 Bar::,Wiz:: 等。
在 Objective-C 中,一个类只能继承一个父类,并且只能是 public 的(这和 Java 是一致的)。同样类似 Java,如果你要在子类中调用父类的函数,需要使用 super。
多重继承
Java 同样不允许多重继承。但是它提供了 interface 来模拟多重继承。类似的,Objective-C 也有同样的机制,这就是协议
虚拟性
虚方法
在 Objective-C 中,所有方法都是虚的,因此,没有 virtual 关键字或其等价物。
虚方法重定义
在 Objective-C 中,你可以定义一个没有在 @interface 块里面声明的方法。但这并不是一种替代 private 的机制,因为这种方法实际是能够被调用的(回想下,Objective-C 中方法的调用是在运行期决定的)。不过,这确实能够把接口定义变得稍微干净了一些。
这并不是一种坏习惯,因为有时你不得不重定义父类的函数。由于所有方法都是虚的,你无需像 C++ 一样在声明中显式写明哪些函数是 virtual 的,这种做法就成为一种隐式的重定义。很多继承西 NSObject 的方法都是是用这种方法重定义的。例如构造方法 init,析构方法 dealloc,view 类的 drawRect: 等等。这样的话,接口就变得更简洁,更易于阅读。不好之处就是,你不能知道究竟哪些方法被重定义了。
纯虚方法则是使用正式协议
虚继承
Objective-C 中不允许多重继承,因此也就没有虚继承的问题。
协议
Java 和 C# 使用接口 interface 的概念来弥补多重继承的不足。Objective-C 也使用了类似的机制,成为协议 protocol。在 C++ 中,这种概念是使用抽象类。协议并不是真正的类:它只能声明方法,不能添加数据。有两种类型的协议:正式的 formal 和非正式的 informal。
正式协议
正式协议的方法,所有实现这个协议的类都必须实现。这就是一种验证,也就是说,只要这个类说实现这个协议,那么它肯定可以处理协议中规定的方法。一个类可以实现任意多个协议。
C++
Objective-C
C++ 中,协议可以由抽象类和纯虚函数实现。C++ 的抽象类要比 Objective-C 的协议强大的多,因为抽象类可以带有数据。
Objective-C 中,协议是一个特殊的概念,使用尖括号 <...> 表明。注意,尖括号在 Objective-C 中不是模板的意思,Objective-C 中没有类似 C++ 模板的概念。
一个类也可以不经过协议声明,直接实现协议规定的方法。此时,conformsToProtocol: 方法依然返回 NO。出于性能考虑,conformsToProtocol: 方法只检查类接口的声明,不会一个方法一个方法的对比着检查。conformsToProtocol: 的返回值并不会作为是否调用方法的依据。下面是这个方法的原型:
实现了正式协议的对象的类型同协议本身是兼容的。这一机制可以作为协议的筛选操作。例如:
可选方法
有时我们需要这么一种机制:我们的类需要实现一部分协议中规定的方法,而不是整个协议。例如在 Cocoa 中,代理的概念被广泛使用:一个类可以给定一个辅助类,由这个辅助类去完成部分任务。
一种实现是将一个协议分割成很多小的协议,然后这个类去实现一个协议的集合。不过这并不具有可操作性。更好的解决方案是使用非正式协议。在 Objective-C 1.0 中就有非正式协议了,Objective-C 2.0 则提出了新的关键字 @optional 和 @required,用以区分可选方法和必须方法。
非正式协议
非正式协议并不是真正的协议,它对代码没有约束力。非正式协议允许开发者将一些方法进行归类,从而可以更好的组织代码。所以,非正式协议并不是协议的宽松版本。另外一个相似的概念就是分类。
让我们想象一个文档管理的服务。假设有绿色、蓝色和红色三种文档,一个类只能处理蓝色文档,而 Slave 类使用三个协议 manageBlueDocuments, manageGreenDocuments 和 manageRedDocuments。Slave 可以加入一个分类 DocumentsManaging,用来声明它能够完成的任务。分类名在小括号中被指定:
任何类都可以加入 DocumentsManaging 分类,加入相关的处理方法:
另一个开发者就可以浏览源代码,找到了 DocumentsManaging 分类。如果他觉得这个分类中有些方法可能对自己,就会检查究竟哪些能够使用。即便他不查看源代码,也可以在运行时指定:
严格说来,除了原型部分,非正式协议对编译器没有什么意义,因为它并不能约束代码。不过,非正式协议可以形成很好的自解释性代码,让 API 更具可读性。
转载时请标明文章原始出处: http://www.devbean.info/2011/03/from_cpp_to_objc_7/