According to Hoyle...
Objective-C for C++ Programmers, Part I
[ Part I | Part II ]
September
2008
by Jonathan Hoyle
jonhoyle@mac.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 such books tend to belabor
elementary concepts. Advanced Objective-C books are as equally
unhelpful, given that they are geared toward those already fluent in the
language. The intention behind the next two articles is
to give the competent C++ programmer an understanding of how to translate
what he or she already knows, into this (perhaps foreign) dialect.
Unlike languages such as
Java,
PHP,
Ruby
and others, Objective-C's strange syntax is so unusual, that it often puts off developers who would
otherwise be interested in taking the time to learn the language.
The goal of this two-part study 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
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 as [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
classcalled
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.getDistanceFromOriginXandY(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 andY: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 withOtherParm:(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 withOtherParm:(int)myParm2;
The first thing you'll note is that member function declarations begin
with a - (dash) 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:withOtherParm:".
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!
[ Part I | Part II ]
See a list of all the According to Hoyle columns
http://www.maccompanion.com/macc/archives/September2008/Columns/AccordingtoHoyle37.htm