From C++ to Objective-C
Contents(目录)
Table of contents (章节目录)
Introduction (导言)
1 Objective-C and Cocoa
1.1 A short history of Objective-C (Objective-C的简短历史). . . . . . . . . . . . . . . . . . . . . . . .. . . . . 6
1.2 Objective-C 2.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 6
2 Syntax overview (符号总介)
2.1 Keywords (关键词). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 7
2.2 Comments(注释) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 7
2.3 Mixing up code and declarations (混合编码和声明). . . . . . . . . . . . . . . . . . . . . . . .. . . . 7
2.4 New types and values (类型和值). . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 7
2.4.1 BOOL, YES, NO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7
2.4.2 nil, Nil and id . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . 7
2.4.3 SEL . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . 8
2.4.4 @encode . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . 8
2.5 Organization of source code: .h and .m files, inclusion (源码文件). . . . . . . . . . .. . . . . 8
2.6 Class names: why NS?(命名空间) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 8
2.7 Differencing functions and methods(不同的函数和方法) . . . . . . . . . . . . . . . . . . . . . .. . . . . 9
3 Classes and objects (类和对象)
3.1 Root class, type id, nil and Nil values . . . . . .. . . . . . . . . . . . . . . . . . 10
3.2 Class declaration (类声明). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 10
3.2.1 Attributes and methods (属性和方法). . . . . . . . . . . . . . . . . . . . . . . . . . . .. 10
3.2.2 Forward declarations: @class, @protoco(前向声明)l . . . . . . . . . . . . . . . . . . .11
3.2.3 public, private, protected .. . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.4 static attributes . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . 12
3.3 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 12
3.3.1 Prototype and call, instance methods, class methods . . . . . . . . . . . . .12
3.3.2 this, self and super . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . 13
3.3.3 Accessing instance variables inside a method(在方法内访问实例变量) . . . . . . . . . . . . . . . . .14
3.3.4 Prototype id and signature, overloading . . . . . . . . . . . . . . . . . . . .14
3.3.5 Pointer to member function: Selector (指向成员函数). . . . . . . . . . . . . . . . . . . . .. 15
3.3.6 Default values of parameters (参数的默认值). . . . . . . . . . . . . . . . . . . . . . . . .. 18
3.3.7 Variable number of arguments(可变参数) . . . . . . . . . . . . . . . . . . . . . . . . .18
3.3.8 Anonymous arguments (匿名参数). . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18
3.3.9 Prototype modifiers (const, static, virtual, “= 0“, friend, throw) . . . 18
3.4 Messages and transmission . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 19
3.4.1 Sending a message to nil . . . . . . . . .. . . . . . . . . . . . . . . . . . . 19
3.4.2 Delegating a message to an unknown object . . . . . . . . . . . . . . . . . .19
3.4.3 Forwarding: handling an unknown message . . . . . . . . . . . . . . . . . . 19
3.4.4 Downcasting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 20
4 Inheritance (继承)
4.1 Simple inheritance(单继承) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 21
4.2 Multiple inheritance (多继承). . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 21
4.3 Virtuality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 21
4.3.1 Virtual methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 21
4.3.2 Silent redefinition of virtual methods . . . . . . . . . . . . . . . . . . . .. . 21
4.3.3 Virtual inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 21
4.4 Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 22
4.4.1 Formal protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 22
4.4.2 Optional methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 23
4.4.3 Informal protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 23
4.4.4 Object of type Protocol. . . . . . . . .. . . . . . . . . . . . . . . . . . . . 24
4.4.5 Message qualifiers for distant objects . . . . . . . . . . . . . . . . . . . .. . 24
4.5 Class categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 25
4.6 Joint use of protocols, categories, subclassing: . . . . . . . . . . . . . . .. . . . . . 26
5 Instantiation (实例)
5.1 Constructors, initializers . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 27
5.1.1 Distinction between allocation andinitialization. . . . . . . . . . . . . . . 27
5.1.2 Using alloc and init . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 27
5.1.3 Example of a correct initializer . . . . . . . . . . . . . . . . . . . . . . .. . 28
5.1.4 self = [superinit...] . . . . . . . . .. . . . . . . . . . . . . . . . . . . 29
5.1.5 Initialization failure . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . 30
5.1.6 “Splitting” construction into alloc+init . . . . . . . . . . . . . . . . . . .31
5.1.7 Default constructor : designated initializer . . . . . . . . . . . . . . . . .. . 32
5.1.8 List of initialization and default value of instance data . . . . . . . . . . .. 34
5.1.9 Virtual constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 34
5.1.10 Class constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 34
5.2 Destructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 34
5.3 Copy operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 35
5.3.1 Classical cloning, copy, copyWithZone:, NSCopyObject() .. . . . . . . . . 35
5.3.2 NSCopyObject() . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 36
5.3.3 Dummy-cloning, mutability, mutableCopy andmutableCopyWithZone:. . 37
6 Memory management (内存管理)
6.1 new and delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . 39
6.2 Reference counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 39
6.3 alloc, copy, mutableCopy,retain, release . . . . . . . . . . . . . . . . . . . . . 39
6.4 autorelease . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . 39
6.4.1 Precious autorelease . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . 39
6.4.2 The autorelease pool . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 41
6.4.3 Using several autorelease pools . . . . . . . . . . . . . . . . . . . . . . . .. 41
6.4.4 Caution with autorelease . . . . . . . . . . . . . . . . . . . .. . . . . . . 41
6.4.5 autorelease and retain . . . . . . . . . . . . . . . . . . . . . . . . . . . .42
6.4.6 Convenience constructor, virtual constructor . . . . . . . . . . . . . . . . .42
6.4.7 Setter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . 44
6.4.8 Getters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 46
6.5 Retain cycles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 48
6.6 Garbage collector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 48
6.6.1 finalize . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 48
6.6.2 weak, strong . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 48
6.6.3 NSMakeCollectable() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 48
6.6.4 AutoZone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 48
7 Exceptions (异常)
8 Multithreading (多线程)
8.1 Thread-safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 51
8.2 @synchronized . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . 51
9 Strings in Objective-C
9.1 The only static objects in Objective-C . . . . . . . . . . . . . . . . . . . .. . . . . 52
9.2 NSString and encodings . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . 52
9.3 Description of an object, %@ format extension,NSString to C string . . . . . . . . . 52
10 C++ specific features
10.1 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 53
10.2 Inlining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 53
10.3 Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 53
10.4 Operators overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 53
10.5 Friends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 53
10.6 const methods . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . 53
10.7 List of initialization in the constructor . . . . . . . . . . . . . . . . . . .. . . . . . 53
11 STL and Cocoa (STL和Cocoa容器)
11.1 Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 54
11.2 Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 54
11.2.1 Classical enumeration . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 54
11.2.2 Fast enumeration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 55
11.3 Functors (function objects) . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 55
11.3.1 Using selectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 55
11.3.2 IMP caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 55
11.4 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 55
12 Implicit code (隐式代码)
12.1 Key-value coding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 56
12.1.1 Principle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 56
12.1.2 Interception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . 57
12.1.3 Prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 57
12.1.4 Advanced features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 57
12.2 Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . 58
12.2.1 Use of properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 58
12.2.2 Description of properties . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 58
12.2.3 Properties attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 59
12.2.4 Custom implementation of properties . . . . . . . . . . . . . . . . . . . . .60
12.2.5 Syntax to access properties . . . . . . . . . . . . . . . . . . . . . . . . . .. 60
12.2.6 Advanced details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 61
13 Dynamism (动态指向)
13.1 RTTI (Run-Time Type Information) . . . . . . . . . . . . . . . . . . . . . . .. . . 62
13.1.1 class, superclass, isMemberOfClass,isKindOfClass . . . . . . . . . . . 62
13.1.2 conformsToProtocol . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . 62
13.1.3 respondsToSelector, instancesRespondToSelector . . . . . . . . . . . . 62
13.1.4 Strong typing or weak typing with id . . . . . . . . . . . . . . . . . . . . . 63
13.2 Manipulating Objective-C classes at run-time . . . . . . . . . . . . . . . . .. . . . 63
14 Objective-C++
15 The future of Objective-C
15.1 The blocks . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . 64
15.1.1 Support and use cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 64
15.1.2 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . 65
15.1.3 Capturing the environment . . . . . . . . . . . . . . . . . . . . . . . . . . .65
15.1.4 __block variables . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 65
Conclusion(总结)
References (引用)
Document revisions (文章增删和修订)
Index (索引)
Introduction
This document is designed to act as a bridge between C++ and Objective-C. Many texts exist
to teach the object model through Objective-C, but to my knowledge, none targetadvanced C++
developers wanting to compare these concepts with their own knowledge. At first, theObjective-C
language seems to be an obstacle rather than a boost for Cocoaprogramming (cf. section 1 on the
following page): it was so different that I couldn’t get into it. It took me some time toappreciate its
challenges,and understand the many helpful concepts it supplies. This document is not atutorial,
but a quick reference, to these concepts. I hope that it will be useful inpreventing a developer
from either abandoning Objective-C or misusing its features, because of amisunderstanding of
the language. This document does not claim to be a full reference, but aquickone. For detailed
explanations of a concept, be sure to read a specialized Objective-C manual [4].
Making comparisons with C# would require another document, becausethat language is much
closer to Objective-C than C++ can be. Thus, a C#developer would certainly learnObjective-C
faster.According to me, C# is, despite a bunch of advancedconcepts, far less interesting than
Objective-C,because it gives hard access to simple Objective-C features, and the Cocoa API quality
is miles ahead of .NET. This personal opinion is not thesubject of the present document.
1 Objective-C and Cocoa
An initial distinction should be made : Objective-C is a language, while Cocoa is a set of classes
that contribute to native MacOS X programming. Theoretically, it is possible to useObjective-C
without Cocoa: there is a gcc front-end. But under MacOS X, both are almostinseparable, as
most of the classes supplied by the language are part of Cocoa.
More precisely, Cocoa is the implementation by Apple, for MacOS X, of the OpenStepstandard,
originally published in 1994. It consists of a developer framework based upon Objective-C.The
GNU step project [6] is another implementation, which is free. Its goal is to be as portableas
possible on most Unix systems, and is still under development.
1.1 A short history of Objective-C
It is hard to give a precise date of birth for a language, owing to the fact thatthere is some
time between first steps, improvements, standardisation and official announcement.However, a
rough history is given in Figure 1 to get a quick look at Objective-C amongst itsancestors and
“challengers”.
19721978 1980 1983 1989 1995 1998-99
Smalltak-72Smalltak-80
C ANSI C C 99
C++ Standard C++ C++0x draft
Objective-CObjective-C 2.0
Objective-C++
Java
C
Figure1: Timeline of Java, C, C#, C++ and Objective-C
Smalltalk-80 is one the first “real” object languages. C++and Objective-C are two different
branches that build a superset of the C language. Objective-C is very close to Smalltalkin terms
of syntax and dynamism, while C++ is much morestatic, with the goal of having better run-time
performance.Java targets a C++ audience, but is also very inspired bySmalltalk for its object
model.That’s why, despite this document’s title, many references are made to Java.The C#
language,developed by Microsoft, is a direct challenger to Objective-C.
Objective-C++ is a kind of merge between Objective-Cand C++. It is already usable, but some
behaviours are still not perfect. The goal of Objective-C++is to mix up the syntaxes of Objective-C
and C++ to benefit from the best features ofboth worlds (cf. section 14 on page 64).
1.2 Objective-C 2.0
The present document has been updated to take in account the new features ofObjective-C 2.0,
which has been released alongside MacOS X10.5. Those features are deep technicalimprovements,
but the high-level modifications for the developers are easily enumerable. They cannow use:
• a garbage-collector : cf. section 6.6 on page 48;
• properties : cf. section 12.2 on page 58;
• fast enumeration : cf. section 11.2.2 on page 55;
• new keywords @optional and @required forprotocols : cf. section 4.4 on page 22;
• updated run-time Objective-C library features : cf.section 13.2 on page 63.
Each one is detailed in a specific section.
2 Syntax overview
2.1 Keywords
Objective-C is a superset of the C language. Like with C++, a well-written C program should be
compile-able as Objective-C, as long as it is not using some of the bad practices allowed byC.
Objective-C has only added some concepts and their associated keywords. To avoid conflicts,these
keywords begin with the @ (at) character. Here is the (short) exhaustive list: @class, @interface,
@implementation, @public, @private, @protected, @try, @catch, @throw, @finally, @end,
@protocol, @selector, @synchronized,@encode, @defs (no more documented in [4]). Objective-C
2.0(cf. 1.2 on the preceding page) has added @optional, @required, @property, @dynamic,
@synthesize. Let us alo quote the values nil et Nil, the types id, SEL and BOOL, the boolean
values being YES et NO. At last, a few kewords are available in particularcontexts, and are not
reserved outside: in, out, inout, bycopy, byref, oneway (they can be metwhen defining protocols
:cf. section 4.4.5 on page 24) and getter, setter, readwrite, readonly, assign, retain, copy,
nonatomic(they can be metwhen defining properties : cf. section 12.2 on page 58).
There is an easy confusion between the language keywords and some methods inheritedfrom the
root class NSObject (the mother of every class, cf. section3.1 on page 10). For instance, the similarlooking
“keywords” for memory managament, named alloc, retain, release and autorelease,
are in fact methods of NSObject. The words super and self (cf. section 3.3.1on page 12), could
also be understood as keywords, but self is in fact ahidden parameter to each method, and super
an instruction asking the compiler to use self differently. However, the confusion between these
false keywords and the true ones will not likely prove problematic in normal use.
2.2 Comments
The comments /* . . . */ and // are allowed.
2.3 Mixing up code and declarations
Like in C++, it is possible to insert thedeclaration of a variable in the middle of a block of
instructions.
2.4 New types and values
2.4.1 BOOL, YES, NO
In C++, the boolean type is bool. In Objective-C, it is BOOL, which can be set to YES or NO.
2.4.2 nil, Nil and id
These three keywords are explained later in the document, but briefly:
• Every object is of type id. This is a tool for weak-typing;
• nil is the equivalentof NULL for a pointer to an object. nil and NULL should not be
interchangeable.
• Nil is the equivalentof nil for a class pointer. In Objective-C, aclass is an object (it is the
instance of a meta-class).
2.4.3 SEL
The SEL type can store selectors values, which are method identifiersunrelated to any class instance
object.These values can be computed by a call to @selector. A selector can be used as a kind of
pointer to a method, even if it is not technically a real pointer to a function. Seesection 3.3.5 on
page15 for more details.
2.4.4 @encode
For the purpose of interoperability, teh data types in Objective-C, even customtypes, and prototypes
of functions or methods, can be ASCII-encoded, according to a documented format[4]. A
call to @encode(a type ) returns a C string (char*) representing the type.
2.5 Organization of source code: .h and .m files, inclusion
Like in C++, it is useful to split the codebetween interface and implementation for each class.
Objective-C uses .h files for headers, and .m files for the code;.mmfiles are used for Objective-C++
(see Section 14 on page 64). Objective-C introduces the #import directive to replace #include.
Indeed, every C header should use compilation guards to prevent multiple inclusions.This is automatic
when using #import. Below is a typicalinterface/implementation example. The Objective-C
syntax is explained later.
C++
//In file Foo.h
#ifndef __FOO_H__ //compilation guard
#define __FOO_H__ //
class Foo
{
...
};
#endif
//In file Foo.cpp
#include "Foo.h"
...
Objective-C
//In file Foo.h
//class declaration, different from
//the "interface" Java keyword
@interface Foo : NSObject
{
...
}
@end
//In file Foo.m
#import "Foo.h"
@implementation Foo
...
@end
2.6 Class names: why NS?
In this document, almost all class names begin with NS, likeNSObjectorNSString. The reason
is simple: they are Cocoa classes, and most Cocoa classes begin withNSsince they were initiated
under NeXTStep.
It is a common practice to use a prefix to identify the origin of a class.
2.7 Differencing functions and methods
Objective-C is not a language with “function calls using square brackets”. This would be alegitimate
thought when observing code like that :
[object doSomething];
insteadof
object.doSomething();
But in fact, Objective-C is a superset of C, so that functionsmatch the same syntax and semantics
as C for declaration, implementation and call. On the contrary, methods, which do not exist in
C, have a special syntax, which includes square brackets. Moreover, the differenceis not only in
the syntax, but also the meaning. This is detailed further in Section 3.2 on thenext page: this
is not a method call, this is sending a message. This is not just a simpleacademic distinction;
it has implications on the mechanism of Objective-C. Even if it is the sameregarding the source
code organization, this mechanism allows much more dynamism. For instance, it iscompatible
with adding a method at run-time (cf. section 13.2 on page 63). The syntax is alsomore readable,
especially with nested calls (cf. section 3.3.1 on page 12).
3 Classes and objects
Objective-C is an object-oriented language: it manages classes and objects. Objective-Cuses a
strict object model, unlike C++ which has manydiscrepancies against the ideal object model. For
instance, in Objective-C, classes are objects and can be dynamically managed: it ispossible to add
classes at run-time, create instances based on the name of the class, ask a class forits methods,
and so on. This is much more powerful than C++ RTTI (cf. section 13.1 on page 62), which have
been added to a very “static” language. Discouraging RTTI use is common since theresults may
depend on the compiler itself and lack portability.
3.1 Root class, type id, nil and Nil values
In an object-oriented language, each program makes use of a set of classes. UnlikeC++, Objective-C
defines a root class. Every new class should be a descendant of the root class. InCocoa, that class
is NSObject, and it provides a huge number offacilities for the run-time system. The root class
notion is not specific to Objective-C; it’s related to the object model. Smalltalk andJava make
use of a root class, while C++ does not.
Strictly speaking, every object should be of type NSObject, and every pointer to an object
could be declared as NSObject*. In fact, one can use the type id instead. This is a short and
handy way to declare a pointer to any object, and provides dynamic type-checkinginstead of static
type-checking. It is very useful for some weak typing on generic methods. Please note that anull
pointer to an object should be set to nil, not NULL. These values are not interchangeable.A normal
C pointer can be set to NULL, but nil was introduced inObjective-C for pointers to objects. In
Objective-C, classes are also objects (meta-class instances), and it is possible to declarea pointer
toa class. Their null value is Nil.
3.2 Class declaration
It is hard to show with a single example all the differences between Objective-Cand C++for class
declaration and implementation. Syntax and concepts are interleaved and requireexplanation. In
the following, the differences are exposed sequentially and specifically.
3.2.1 Attributes and methods
In Objective-C, attributes are called instance data, and member functions are calledmethods.
C++ Objective-C
class Foo
{
double x;
public:
int f(int x);
float g(int x, int y);
};
int Foo::f(int x) {...}
float Foo::g(int x, int y) {...}
@interface Foo : NSObject
{
double x;
}
-(int) f:(int)x;
-(float) g:(int)x :(int)y;
@end
@implementation Foo
-(int) f:(int)x {...}
-(float) g:(int)x :(int)y {...}
@end
In C++, attributes and methods are declaredtogether inside the braces of the class. Method
implementation syntax is similar to C, with the addition of the scope resolution operator (Foo:: ).
In Objective-C, attributes and methods cannot be mixed. The attributesare declared in braces,
the methods follow. Their implementation lies in an @implementation block.
This is a major difference with C++, since somemethods can be implemented without being
exposed in the interface. This is detailed later. Briefly, this is a way to clean upheader files by
removing unnecessary declarations (“private” methods, and silently redefined virtualmethods like
destructors). Please see Section 4.3.2 on page 21 for further explanations.
Instance methods are prefixed by the minus symbol “-”, and class methods by the plussymbol
“+” (cf.section 3.3.9 on page 18); this symbol has nothing to do with the UML notationand
the meaning public or private. The type of the parameters are enclosed in parenthesis,and the
parameters are separated by the symbol “:”. Please see Section 3.3.1 on the next page forfurther
explanations on the syntax of prototypes.
In Objective-C, there is no need for a semi-colon at the end of a classdeclaration. Also note
that the keyword to declare a class is @interface and not @class. The keyword @class is only
used in forward declarations (cf. section 3.2.2 on the current page). Finally, ifthere is no instance
data in a class, the braces, which would enclose nothing, can be ommitted.
3.2.2 Forward declarations: @class, @protocol
To avoid cyclic dependencies in header files, the C language supports theforward declaration,
that allows the coder to declare a class when the only required knowledge is itsexistence and
not its structure. In C++, the keyword class is used; in Objective-C, it is @class. The keyword
@protocol can also be usedto anticipate the declaration of a protocol (cf. section 4.4 on page 22).
C++
//In file Foo.h
#ifndef __FOO_H__
#define __FOO_H__
class Bar; //forward declaration
class Foo
{
Bar *bar;
public:
void useBar(void);
};
#endif
//In file Foo.cpp
#include "Foo.h"
#include "Bar.h"
void Foo::useBar(void)
{
...
}
Objective-C
//In file Foo.h
@class Bar; //forward declaration
@interface Foo : NSObject
{
Bar *bar;
}
-(void) useBar;
@end
//In file Foo.m
#import "Foo.h"
#import "Bar.h"
@implementation Foo
-(void) useBar
{
...
}
@end
3.2.3 public, private, protected
One major feature of the object model is data encapsulation, which limits the visibility of data to
some parts of the code, in order to ensure its integrity.
C++ Objective-C
class Foo
{
public:
int x;
int apple();
protected:
int y;
int pear();
private:
int z;
int banana();
};
@interface Foo : NSObject
{
@public
int x;
@protected:
int y;
@private:
int z;
}
-(int) apple;
-(int) pear;
-(int) banana;
@end
In C++, attributes and methods can belong to a public, protected or private scope. The
default mode is private.
In Objective-C, only the instance data can be public, protected or private, and the default
visibility is protected. Methods can only be public. However, it is possible to mimic the private
mode, by implementing some methods in the @implementation, without declaring them in the
@interface, or using the notion of class category (cf. section 4.5 on page 25). It does not prevent
methods from being called, but they are less exposed. Implementing a method without a previous
declaration is a special property of Objective-C and has a specific purpose, as explained in
Section 4.3.2 on page 21.
Inheritance cannot be tagged public, protected or private. The only way is public. Inheritance
in Objective-C looks more like Java than C++ (section 4 on page 21).
3.2.4 static attributes
It’s not possible in Objective-C to declare a class data attribute (static as in C++). However, it
is possible to do the same thing in a different way: use a global variable in the implementation file
(optionally with the static C keyword to limit the scope). The class can then use accessors on
it (with class methods or normal methods), and its initialization can be done in the initialize
method of the class (cf. section 5.1.10 on page 34).
3.3 Methods
The syntax for a method in Objective-C is different from the syntax for common C functions. This
section aims to describe this syntax and adds some information on the underlying message sending
principle.
3.3.1 Prototype and call, instance methods, class methods
• A method is prefixed by “−” if it is an instance method (common case), or by “+” if it is
a class method (static in C++). This symbol is in no way linked to the UML notation for
public or private. Methods are always public in Objective-C;
• the types for the return value, or for the parameters, are enclosed by parentheses;
• the parameters are separated by a colon “:”;
• the parameters can be associated with a label, a name specified just before “:”; the label
is then part of the name of the method and modifies it. That makes calls to this
function particularly readable. In fact, the label usage should be systematic. Note that the
first parameter cannot have a label – indeed, its label is already the name of the method;
• a method name can be the same as an attribute name, without conflict. This is very useful
for getters (cf. section 6.4.8 on page 46).
C++
//prototype
void Array::insertObject(void *anObject, unsigned int atIndex)
//use with a "shelf" instance of the Array class and a "book" object
shelf.insertObject(book, 2);
Objective-C
Without label (direct translation from C++)
//prototype
//The method is named "insertObject::", the colon being used to separate
//the parameters (it is not a scope resolution operator like in C++)
-(void) insertObject:(id)anObject:(unsigned int)index
//use with a "shelf" instance of the Array class and a "book" object
[shelf insertObject:book:2];
With label
//prototype. The "index" parameter is now labeled "atIndex"
//The method is now named "insertObject:atIndex:"
//The call can easily be read like a sentence
-(void) insertObject:(id)anObject atIndex:(unsigned int)index
//use with a "shelf" instance of the Array class and a "book" object
[shelf insertObject:book:2]; //Error !
[shelf insertObject:book atIndex:2]; //OK
Please note that the syntax with square brackets should not be read as calling the method
insertObject of object “shelf” but rather sending the message insertObject to object “shelf”.
This is what makes Objective-C. One can send any message to any target. If it is not able to
handle the message, it can ignore it (an exception is raised but the program does not abort). If,
at the time it receives the message, a target is able to handle it, then the matching method will
be called. The compiler is able to raise a warning if a message is sent to a class for which it is
known that no matching method exists. This is not considered as an error thanks to the forwarding
facility (cf. section 3.4.3 on page 19). If a target is only known under the type id, no warning will
be made at compile time; a potential error would be raised at run-time.
3.3.2 this, self and super
There are two particular targets for a message: self and super. self is the current object (like
this in C++), super is the parent class. The keyword this does not exist in Objective-C. It is
replaced by self.
NB: self is not a real keyword, it is a hidden parameter that each method receives, the value
of which is the current object. Its value can be changed, unlike C++’s this keyword. However,
this is only useful in constructors (cf. section 5.1 on page 27).
3.3.3 Accessing instance variables inside a method
Like in C++, an Objective-C method can access the instance variables of its current object. The
optional this-> in C++ can be written self->.
C++ Objective-C
class Foo
{
int x;
int y;
void f(void);
};
void Foo::f(void)
{
x = 1;
int y; //making ambiguity with this->y
y = 2; //using local y
this->y = 3; //disambiguating
}
@interface Foo : NSObject
{
int x;
int y;
}
-(void) f;
@end
@implementation Foo
-(void) f
{
x = 1;
int y; //making ambiguity with this->y
y = 2; //using local y
self->y = 3; //disambiguating
}
@end
3.3.4 Prototype id and signature, overloading
A function is a part of code that can be referenced, for instance to use as function pointers, or
functors. Moreover, even if the name of the function is a good candidate for a unique id, one
must take care when using overloading. C++ and Objective-C use opposite ways to differentiate
prototypes. The first is based on parameters types, while the second is based on parameter labels.
In C++, two functions can have the same name as long as their parameters have different types.
When using methods, the const option is also discriminative.
C++
int f(int);
int f(float); //OK, float is different from int
class Foo
{
public:
int g(int);
int g(float); //OK, float is different from int
int g(float) const; //OK, const is discriminative
};
class Bar
{
public:
int g(int); //OK, we are in Bar::, different from Foo::
}
In Objective-C, all functions are C functions: they cannot be overloaded (unless the compiler
can be told to use C99; like gcc does). However, methods use a different syntax, and can be
differentiated thanks to parameter labels.
Objective-C
int f(int);
int f(float); //Error : C functions cannot be overloaded
@interface Foo : NSObject
{}
-(int) g:(int) x;
-(int) g:(float) x; //Error : this method is not different
// from the previous one (no label)
-(int) g:(int) x :(int) y; //OK : two anonymous labels
-(int) g:(int) x :(float) y; //Error : not different from the
//previous one
-(int) g:(int) x andY:(int) y; //OK : second label is "andY"
-(int) g:(int) x andY:(float) y; //Error : not different from the
//previous one
-(int) g:(int) x andAlsoY:(int) y; //OK : second label is
//"andAlsoY", different from "andY"
@end
The label-based identifying method is useful for expressing the exact “name” of the function,
as stated below.
@interface Foo : NSObject {}
//The method name is "g"
-(int) g;
//The method name is "g:"
-(int) g:(float) x;
//The method name is "g::"
-(int) g:(float) x :(float) y;
//The method name is "g:andY:"
-(int) g:(float) x andY:(float) y;
//The method name is "g:andZ:"
-(int) g:(float) x andZ:(float) z
@end
Clearly, two Objective-C methods are differentiated by labels instead of types. This is a way to
replace “pointers on member functions”, expressed by selectors, as explained in section 3.3.5 on
the current page.
3.3.5 Pointer to member function: Selector
In Objective-C, the methods have a particular syntax using parentheses and labels. It is not
possible to declare functions with this syntax. The notion of pointer to functions is the same in C
and Objective-C. It is only for pointers on methods where a difference occurs.
In C++, the syntax is hard but consistent with the C langage : the pointer focus is on types.
C++
class Foo
{
public:
int f(float x) {...}
};
Foo bar
int (Foo::*p_f)(float) = &Foo::f; //Pointer to Foo::f
(bar.*p_f)(1.2345); //calling bar.f(1.2345);
In Objective-C, a new type has been introduced. Such a “pointer to a method” is called
a selector. Its type is SEL and its value is computed using @selector on the exact name of the
method (with labels of parameters). Calling the method can be done using the class NSInvocation.
Most of the time, utility methods of the performSelector: family (inherited from NSObject) are
handier, but a little restrictive. The simplest three ones are:
-(id) performSelector:(SEL)aSelector;
-(id) performSelector:(SEL)aSelector withObject:(id)anObjectAsParameter;
-(id) performSelector:(SEL)aSelector withObject:(id)anObjectAsParameter
withObject:(id)anotherObjectAsParameter;
The returned value is the same as that of the called method. For methods which have parameters
that are not objects, one should generally use wrapper classes like NSNumber, that can provide
float, int, and so on. The NSInvocation class, which is more general and powerful, can also be
used (see the documentation).
According to what has been said, nothing prevents a method from being called on an object,
even if the object does not implement it. In fact, the method is effectively triggered if the message
is accepted. But an exception, that can be caught, is raised when the object does not know the
method; the application is not interrupted. Moreover, it is possible to check that an object can
trigger a method by calling respondsToSelector:.
Finally, the value of @selector() is computed at compile-time, which does not slow down the
code.
Objective-C
@interface Slave : NSObject {}
-(void) readDocumentation:(Document*)document;
@end
//Let us suppose an array "array[]" of 10 slaves,
//and a document "document"
//Normal method call
for(i=0 ; i<10 ; ++i)
[array[i] readDocumentation:document];
//Just for the example, try to use performSelector: instead
for(i=0 ; i<10 ; ++i)
[array[i] performSelector:@selector(readDocumentation:)
withObject:document];
//The type of a selector is SEL
//The following version is not more efficient than the previous one,
//since @selector() is evaluated at compile-time
SEL methodSelector = @selector(readDocumentation:);
for(i=0 ; i<10 ; ++i)
[slaves[i] performSelector:methodSelector withObject:document];
//for an object "foo" which type is not known (id)
//the test is not mandatory, but prevents an exception to be raised
//if the object has no readDocumentation: method.
if ([foo respondsToSelector:@selector(readDocumentation:)])
[foo performSelector:@selector(readDocumentation:) withObject:document];
A selector can thus be used as a very simple function parameter. Generic algorithms, like
sorting, may be easily specialized that way (cf. 11.3 on page 55).
A selector is not, strictly speaking, a pointer to a function; its real underlying type is a C
string, registered by the run-time as a method identifier. When a class is loaded, its methods
are automatically registered in a table, so that @selector() can work as expected. This way, for
instance, the equality of two selectors can be done on adresses with == rather than reyling on a
string comparison.
The real adress of a method, seen as a C function, can be obtained with a different notion,
and the type IMP, that is briefly presented in section 11.3.2 on page 55. It is rarely used but for
optimization. Virtual calls, for instance, are handled by selectors but not by IMP. The Objective-C
equivalent for C++ method pointers is definitely in selectors.
Finally, you may remember that self is in Objective-C, like this in C++, a hidden parameter
of every method that stores the current object. You can also note that there is a second hidden
parameter, _cmd, which is the current method .
Objective-C
@implementation Foo
-(void) f:(id)parameter //equivalent to a C function of type
//"void f(id self, SEL _cmd, id parameter)"
{
id currentObject = self;
SEL currentMethod = _cmd;
[currentObject performSelector:currentMethod
withObject:parameter]; //recursive call
[self performSelector:_cmd withObject:parameter]; //idem
}
@end
3.3.6 Default values of parameters
Objective-C does not allow a default value to be specified for the parameters of functions or methods.
One should create as much functions as necessary when some parameters could be optional.
In the case of constructors, one should use the notion of designated initializer (section 5.1.7 on
page 32).
3.3.7 Variable number of arguments
Objective-C allows the use of methods with a variable number of arguments. Like in C, the syntax
relies on using “...” as the last argument. This is rarely useful, even if many Cocoa methods are
doing so. More details can be found in the Objective-C documentation.
3.3.8 Anonymous arguments
In C++, it is possible to give no name to a parameter in a prototype, since the type is sufficient to
characterize the signature of a function. This is not possible in Objective-C.
3.3.9 Prototype modifiers (const, static, virtual, “= 0“, friend, throw)
In C++, a few modifiers can be added to the prototype of a function. None of them exist in
Objective-C. Here is the list:
• const: a method cannot be set const. As a consequence, the mutable keyword cannot exist;
• static: making the difference between an instance method and a class method is done
through the use of “-” or “+” in front of the prototype;
• virtual: Objective-C methods are virtual, so the keyword is useless. Pure virtual methods
are implemented with a formal protocol (cf. section 4.4 on page 22);
• friend: there is no “friend” notion in Objective-C;
• throw: in C++, one can restrict a method to transmit some exceptions only. This is not
possible in Objective-C.
3.4 Messages and transmission
3.4.1 Sending a message to nil
By default, it is legal to send a message (call a method) to nil. The message is just ignored. The
code can be greatly simplified by reducing the number of tests usually made with the null pointer.
GCC has an option to disable that handy behaviour, for extra optimizations.
3.4.2 Delegating a message to an unknown object
Delegation is common with user interface elements in Cocoa (tables, outlines. . . ), taking advantage
of the ability to send a message to an unknown object. An object can, for example, delegate some
tasks to an assistant.
//This is a function to define an assistant
-(void) setAssistant:(id)slave
{
[assistant autorelease]; //see the section about memory management
assistant = [slave retain];
}
//the method performHardWork can use delegation
-(void) performHardWork:(id)task
{
//the assistant is not known
//we check that it can handle the message
if ([assistant respondsToSelector:@selector(performHardWork:)])
[assistant performHardWork:task];
else
[self findAnotherAssistant];
}
3.4.3 Forwarding: handling an unknown message
In C++, code cannot be compiled if a method is called on an object that does not implement it.
In Objective-C, there’s a difference: one can always send a message to an object. If it can’t be
handled at run-time, it will be ignored (and raise an exception); moreover, instead of ignoring it,
it can forward the message to another object.
When the compiler is told the type of an object, it can detect if a message sending – method
call – will fail, and raise a warning. However, this is not an error, since in this case, an alternative is
available. This second chance is represented by a call to the forwardInvocation: method, which
can be redefined to redirect the message at the very last moment. This is obviously a method of
NSObject, which does nothing by default. Here is another way to manage assistant objects.
-(void) forwardInvocation:(NSInvocation*)anInvocation
{
//if we are here, that is because the object cannot handle
//the message of the invocation
//the bad selector can be obtained by sending "selector"
//to the object "anInvocation"
if ([anotherObject respondsToSelector:[anInvocation selector]])
[anInvocation invokeWithTarget:anotherObject];
else //do not forget to try with the superclass
[super forwardInvocation:anInvocation];
}
Even if a message can be handled, at last, in a forwardInvocation:, and only there, a check
based on respondsToSelector: will still return NO. Indeed, the respondsToSelector: mechanism
is not designed to guess whether forwardInvocation: will work or not.
Using the forward invocation can be thought as a bad practice, because it is triggering some
code while an error should occur. In fact , very good uses can be made of that mechanism, like in
the implementation of the Cocoa’s NSUndoManager. It allows an exceptionnaly pleasant syntax :
the Undo manager can records calls to methods, though it is not itself the target of those calls.
3.4.4 Downcasting
Downcasting is needed in C++ to call methods on a subclass, when only a parent class pointer is
known, this is made possible using dynamic_cast. In Objective-C, this practice is not necessary,
since a message can be sent to an object event if it seems that the object cannot handle it.
However, to avoid a compiler warning, one can simply cast the type of the object; there is no
explicit downcasting operator in Objective-C, the traditionnal cast syntax of the C language can
be used.
//NSMutableString is a subclass of NSString (string of characters)
//that allows mutating operations
//the "appendString:" method only exists in NSMutableString
NSMutableString* mutableString = ...initializing a mutable string...
NSString* string = mutableString;//storing in an NSString pointer
//those different calls are all valid
[string appendString:@"foo"];//compiler warning
[(NSMutableString*)string appendString:@"foo"];//no warning
[(id)string appendString:@"foo"];//no warning
4 Inheritance
4.1 Simple inheritance
Objective-C obviously implements the notion of inheritance, but does not support multiple inheritance.
This limitation is addressed by other concepts (protocols, class categories) that are
explained later in this document (sections 4.4 on the following page, 4.5 on page 25).
C++ Objective-C
class Foo : public Bar,
protected Wiz
{}
@interface Foo : Bar //single inheritance
//An alternative technique must be
//used to also "inherit" from Wiz
{}
@end
In C++, a class can be derived from one or several other classes, using public, protected or
private mode. In the methods, one can reference a superclass using the scope resolution operator
:: (Bar::, Wiz::).
In Objective-C, one can derive from one class only, using public mode. A method can reference
the superclass with the (false) keyword super, like in Java.
4.2 Multiple inheritance
Objective-C does not implement multiple inheritance, but brings other concepts, the protocols
(cf. 4.4 on the following page) and the categories (cf. 4.5 on page 25).
4.3 Virtuality
4.3.1 Virtual methods
In Objective-C, all methods are virtual. Hence, the virtual keyword does not exist and has no
equivalent.
4.3.2 Silent redefinition of virtual methods
It is possible in Objective-C to implement a method that has not been declared in the interface
section. This feature does not replace the @private notion for the methods (even if it can be used
to “hide” methods) : they can still be called; but it does lighten the interface declarations.
This is not a bad practice: the methods one uses with this technique are often “well-known”
methods of the super-classes. Many methods of the root-class NSObject are silently redefined. One
can quote the constructor init (cf. section 5.1 on page 27), the destructor dealloc (cf. section 5.2
on page 34), the drawing method drawRect: of views, and so on.
The interfaces are then lighter and easier to read, even if it is more difficult to see what can be
redefined, implying a regular reading of the super class documentation.
The notion of pure virtual methods (a method that must be redefined in sub-classes), is
addressed by the concept of formal protocols (cf. section 4.4.1 on the following page on the next
page).
4.3.3 Virtual inheritance
Virtual inheritance is not relevant in Objective-C, since inheritance cannot be multiple and has
none of the associated problems.
4.4 Protocols
Java and C# fix the lack of multiple inheritance by the notion of interface. In Objective-C, the
same notion is used, and is called a protocol. In C++, this would be an abstract class. A protocol
is not a real class: it can only declare methods and cannot hold any data. There are two types of
protocols : formal and informal.
4.4.1 Formal protocol
A formal protocol is a set of methods that must be implemented in any conforming class. This
can be seen as a certification regarding a class, ensuring that it is able to handle everything that
is necessary for a given service. A class can conform to an unlimited number of protocols.
C++
class MouseListener
{
public:
virtual bool mousePressed(void) = 0; //pure virtual method
virtual bool mouseClicked(void) = 0; //pure virtual method
};
class KeyboardListener
{
public:
virtual bool keyPressed(void) = 0; //pure virtual method
};
class Foo : public MouseListener, public KeyboardListener {...}
//Foo MUST implement mousePressed, mouseClicked and keyPressed
//It can then be used as an event listener for the mouse and the keyboard
Objective-C
@protocol MouseListener
-(BOOL) mousePressed;
-(BOOL) mouseClicked;
@end
@protocol KeyboardListener
-(BOOL) keyPressed;
@end
@interface Foo : NSObject <MouseListener, KeyboardListener>
{
...
}
@end
//Foo MUST implement mousePressed, mouseClicked and keyPressed
//It can then be used as an event listener for the mouse and the keyboard
In C++, a protocol is implemented by an abstract class and pure virtual methods. The abstract
class in C++ is more powerful than the Objective-C protocol since it can contain data.
In Objective-C, the protocol is a specific concept. The syntax using angular brackets <...>
is not linked to the C++ templates, a feature that does not exist in Objective-C.
A class can implement all the methods of a protocol without declaring its conformance. In this
case, the conformsToProtocol: method returns NO. For efficiency reasons, conformsToProtocol:
does not check, method-by-method, the conformance to a protocol, but is based on the explicit
declaration from the developer. However, the negative answer to conformsToProtocol: does not
prevent the program from behaving correctly if the methods of the protocol are called. Here is the
prototype of conformsToProtocol:
-(BOOL) conformsToProtocol:(Protocol*)protocol
//a Protocol object is returned by a call to @protocol(protocol name)
The type of an object that conforms to a formal protocol can be added the name of the protocol
itself, between angular braces. This is useful for assertions. For example :
//the following standard Cocoa method takes one parameter which is of
//any type (id), but must conform to the protocol NSDraggingInfo
-(NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender;
4.4.2 Optional methods
It may be desirable that a class conforms to a protocol, to show that it can handle a particular
service, but without forcing it to conform to the whole protocol. For instance, in Cocoa, the notion
of a delegate object is widely used: an object can be given an assistant, to handle some tasks, but
not all of them.
An immediate solution would be to split a formal protocol into multiple ones, and then make
the class conform to a subset of these protocols. This is not very handy. Cocoa brings a solution
in the notion of informal protocols. With Objective-C 1.0, the informal protocols coudl be used
(cf. section 4.4.3). With Objective-C 2.0, the new keywords @optional and required can make
the difference between optional and required methods.
@protocol Slave
@required //required part
-(void) makeCoffee;
-(void) duplicateDocument:(Document*)document count:(int)count;
@optional //optional part
-(void) sweep;
@required //you can split required/optional sections
-(void) bringCoffee;
@end
4.4.3 Informal protocol
The informal protocol i not really a “protocol” : it creates no constraint upon the code. But
- 上一篇:没有了
- 下一篇: php、javascript、python、ruby语言对比