According to Hoyle...
Objective-C
for C++ Programmers, Part I
September
2008
by Jonathan Hoyle
jhoyle@maccompanion.com
macCompanion
http://www.jonhoyle.com
This month we examine the Objective-C language
from a C++ perspective. Although
there are a large number of Objective-C books written for the beginner, these
are inappropriate to advanced C++ programmers as they tend to belabor
elementary concepts. Advanced
Objective-C books are equally as unhelpful, as these are geared toward those
already fluent in the language. The intention behind the next series of articles is to give the
competent C++ programmer an understanding of how to translate what he or she already
knows into this foreign dialect. Unlike languages such as Java, PHP, Ruby and others, Objective-C's
bizarre syntax is so unusual, that it often puts off developers who would
otherwise be interested in learning it.
The goal of this series is to offer a "translator" of sorts, defining Objective-C terms and
practices in terms of C++ equivalents (or near equivalents). We begin this month with Objective-C
classes: how they are called, declared and defined. For each Objective-C syntax introduction we give, C++ code examples will
be demonstrated as much a possible.
For those looking for more complete documentation
for understanding Objective-C from a C++ perspective, I heartily recommend
reading Pierre Chatelier's From
C++ to Objective-C.
What Do Those Damn
Brackets Mean Anyway?
When C++ programmers see Objective-C code for the
first time, they are often taken aback by the bizarre use of square brackets [
]. In C++, as with C, square
brackets are used almost exclusively for array indexing. But in Objective-C, it has a very
different use: it is encloses an object's invocation of a method. In most modern languages, the syntax
for method invocation involves the dot operator. You can think of the C++ call:
object.method();
as loosely equivalent to Objective-C's:
[object method];
The former syntax is fairly standardized among
most all modern languages. The
latter was borrowed from the object oriented language SmallTalk and is rarely seen outside of Objective-C
development. Note that these calls
can be nested, so that the Objective-C line:
[[[object method1] method2]
method3];
is the same as:
object.method1().method2().method3();
Though such long nestings is generally considered
poor style in C++ (not to mention dereferencing function returns), it is common
practice in Objective-C, so you better get use to it.
One of the most crucial differences though is
that this Objective-C syntax is actually a form of message-passing, not exclusive to method invocation. In C++, method() must be a member
function of the class that object is an instance of. If not, the line object.method(); would fail to compile. In Objective-C, method() need not be
defined for class of which object is an instance. There may be any number of potential runtime resolutions to
the line [object method]; . For
this reason, Objective-C users need to be less reliant on their compiler
catching careless mistakes. A typo
such a [object mehtod]; will not
generate the compiler error that object.mehtod(); would.
Pass the Function
Parameters, Please...
In the above example, method() took no parameters; so how do you handle methods
which do? This is where things get
a little complicated. Fortunately,
passing a single parameter to a method is simple enough though: whereas in C++
the parameter is placed within the function's round brackets:
object.method(parameter);
in Objective-C, the parameter is separated by the
method name by use of the colon:
[object method:parameter];
With two or more parameters, it can get a bit
messy (particularly from a C++ perspective). Rather than use generic terms, it's better to illustrate
with a more specific example. Let's say you have a class called Graph containing a method that obtains
the distance from origin for any point in the plane. The C++ code for such a function might look something like
this:
distance =
myGraph.GetDistanceFromOriginXY(xCoord, yCoord);
In C++, additional parameters are separated by
commas. In Objective-C however,
the actual function name itself is split up:
distance = [myGraph
GetDistanceFromOriginX: xCoord Y: yCoord];
Rather than comma separated, Objective-C method
parameters are preceded by tags which are essentially part of the method name
itself. In general, a call of the
form:
[foo bar1:parm1 bar2:parm2
bar3:parm3];
can be thought of as the Objective-C equivalent
to the standard C++:
foo.bar(parm1, parm2, parm3)
in which the C++ method bar is morphed into the Objective-C method tags bar1, bar2, bar3.
Objective-C Class
Declarations
So now you know how to translate Objective-C
calling code. That (believe it or
not) is the easy part. If you are
creating your own classes, you must declare and define these functions. Even if you are not creating them yourself, you may have
need to read and understand the implementation of these calls.
Let's begin with class declarations. Class declarations are what you
typically find in C++ header files. Below is a typically generic C++ class declaration which we will use as
our basis for porting to Objective-C:
class MyClass: public MyBaseClass
{
public:
MyClass();
virtual ~MyClass();
int PublicMethod();
void PublicMethod(int myParm);
void PublicMethod(double myParm);
void PublicMethod(int myParm1, int myParm2);
static short StaticMethod();
protected:
long ProtectedMethod();
double mProtectedMemberData;
private:
int mPrivateMemberData;
};
As you can see, MyClass has the usual items that you would expect one to
have: a constructor, a destructor, both public and protected methods, protected
member data, and even a private member variable. We see that MyClass is
derived from MyBaseClass. You'll note that the function PublicMethod() is overloaded with four prototypes. Finally, note that we have added a
static member function. This is
nothing fancy and could be the outline for many C++ classes you run into.
This is how this same class might be declared in
Objective-C:
@interface MyClass: MyBaseClass
{
@protected:
double mProtectedMemberData;
@private:
int mPrivateMemberData;
}
-(int)
PublicMethod;
-(void)
PublicMethod: (int)myParm;
-(void)
PublicMethod2: (double)myParm;
-(void)
PublicMethod: (int)myParm1: (int)myParm2;
+(short)
StaticMethod;
-(long)
PublicMethod3;
@end
Okay, getting past the alien looking syntax,
let's examine this line by line. In C++ class declarations are extensions to struct declarations from C,
with the added ability to include functions as members. In Objective-C, a class declaration is
quite different, living between the calls @interface and @end. The @ symbol is used throughout Objective-C to alert the language parser
that this is non C-like syntax.
The first line
@interface MyClass: MyBaseClass
is straightforward enough to understand. Note though the missing word public from the inheritance. This is because in Objective-C, class inheritance can only
be public. Furthermore,
Objective-C does not support multiple inheritance as C++ does.
Next comes the member data:
{
@protected:
double mProtectedMemberData;
@private:
int mPrivateMemberData;
}
Again you'll note the similarity with C++, except
with the strange @ prefix. Although it is poor C++ programming style, you may also have public
member data, and as you might expect, in Objective-C it would be preceded by
the tag @protected:
.
Unlike in C++ however, Objective-C member
functions do not co-mingle with member data. They are listed separately as follows:
-(int)
PublicMethod;
-(void)
PublicMethod: (int)myParm;
-(void)
PublicMethod2: (double)myParm;
-(void)
PublicMethod: (int)myParm1: (int)myParm2;
The first thing you'll note is that member
function declarations begin with a - followed by the return type in parentheses, followed in turn by the
function name. If there are function
parameters, they are listed colon-separated with (once again) the type in
parentheses followed by the name.
You'll notice is that the third C++ prototypes
for PublicMethod() has been given a
different name. This is because
Objective-C, like C, is limited to requiring each function name to be
unique. The first method's name
(as you would expect) is simply "PublicMethod". The second one's name is "PublicMethod:", that is, with a colon suffix indicating a
single parameter. To avoid a name
conflict, the third prototype was renamed, so that its official name would be "PublicMethod2:" rather than "PublicMethod:". The final prototype fails to conflict since its official name is "PublicMethod::".
Static methods are declared similarly to
non-static methods, except with a + prefix:
+(short)
StaticMethod;
Finally, we come to the protected C++ member ProtectedMethod(). Unfortunately, all Objective C member functions are public. No protected or private functions are
allowed. For this reason, we
changed the name of this function:
-(long)
PublicMethod3;
And now we reach the end of the declaration with @end.
You'll notice that we have intentionally skipped
the constructor and destructor in our port of MyClass. In
Objective-C, these concepts are replaced by initialization and allocation and
will be the focus of next month's column. For now, let us pretend they do not exist and we will return to them
next time, I promise.
Objective-C Class
Definitions
Once a class is declared in a header file, it must then be defined in a source file. In C++, this is typically a file using a .cpp extension
(alternatively .cp or .cc). In the
example of MyClass, we would usually find the class declaration in a file
called MyClass.h, the definition in MyClass.cpp, and near the top of the latter file, we would
expect to find the line:
#include "MyClass.h"
Each method of MyClass would be defined separately within MyClass.cpp,
examples of which include:
int MyClass::PublicMethod()
{
... // Actual code
}
void MyClass::PublicMethod(int myParm1, int myParm2)
{
... // Actual code
}
In C++ , methods are defined just like standard C
functions, with the exception that the class name and double colon prefixes the
method name. MyClass:: places the method name PublicMethod() within the scope of the class MyClass. This form of scope resolution is used without C++, not just for classes
but for namespaces as well.
By now, it should comes as no surprise that
Objective-C methods are not defined anything like C++ methods, and that the
strange @ symbol will be key. Although Objective-C header files retain the .h suffix, Objective-C
source files typically use a .m suffix. The inclusion directive is also different, so near the top of MyClass.m,
we would find:
#import "MyClass.h"
The main difference between the Objective-C #import directive and the standard C #include is
that the former suppresses multiple inclusions. To achieve this same affect, C programmers have often use
macros to avoid multiple inclusion, as follows:
//
MyClass.h header file
#ifndef MYCLASS_H
#define MYCLASS_H
... // Class declaration
#endif // MYCLASS_H
Objective-C's #import makes this redundant.
Analogous to method declarations, Objective-C
method definitions must be enclosed within an @implementation scope. The definitions themselves follow the syntax
of the declaration, as the following example shows:
@implementation MyClass
-(int)
PublicMethod
{
... // Actual code
}
-(void)
PublicMethod: (int)myParm1: (int)myParm2
{
... // Actual code
}
//
Remaining method definitions
...
@end
Conclusions So Far...
This month we have learned how to define, declare
and call Objective-C class methods. Yes, Objective-C is very different syntactically. And indeed it is sometimes a little
hard on the eyes. But much of this
is due to its legacy and age. Modern languages have come about during a time when the dot syntax has
become standardized. In the 1980's
when Objective-C was being developed, C++ was also in its infancy, so there was
no way of knowing which convention would win out. The Objective-C 2.0 standard (2007) has made some small
steps to remedy this problem, but there is still a long way to go. Like learning to speak a foreign
language, it takes time and effort to develop fluency.
Coming Up Next Month: More of our investigation of Objective-C from a C++ perspective. See you in 30!
See a list of all the According to Hoyle columns