Learning C++ if you already know Objective-C
What’s the difference between C++ and Objective-C?
Both fully support the OO paradigm. Neither is categorically and universally “better” than the other. But there are differences. The most important differences are:
- Static typing vs. dynamic typing
- Whether inheritance must be used only for subtyping
- Value vs. reference semantics
Note: If you have a Objective-C background, this section will tell you the most important things you need to effectively use C++. Please don’t get the notion that either language is somehow “inferior” or “bad”, or that this section is promoting one language over the other. I am not a language bigot, having served on both the ANSI C++ and ANSI Smalltalk standardization committees, and I don’t recommend language bigotry. Instead, this section is designed to help you understand (and embrace!) the differences.
What is “static typing,” and how is it similar/dissimilar to Objective-C?
Static typing says the compiler checks the type safety of every operation statically (at compile-time), rather than to generate code which will check things at run-time. For example, with static typing, the signature matching for function arguments is checked at compile time, not at run-time. An improper match is flagged as an error by the compiler, not by the run-time system.
In OO code, the most common “typing mismatch” is invoking a member function against an object which isn’t prepared to
handle the operation. E.g., if class
Fred
has member function f()
but not g()
, and fred
is an instance of
class
Fred
, then fred.f()
is legal and fred.g()
is illegal. C++ (statically typed) catches the error at
compile time, and the @
dynamic part@
of Objective-C (dynamically typed) catches the error at run-time.
(Technically speaking, C++ is like Pascal —pseudo statically typed— since pointer casts and unions can be used
to violate the typing system; which reminds me: use pointer casts and unions only as often as you use
goto
s).
Which is a better fit for C++: “static typing” or “dynamic typing”?
[For context, please read the previous FAQ].
If you want to use C++ most effectively, use it as a statically typed language.
C++ is flexible enough that you can (via pointer casts, unions, and #define
macros) make it “look” like
Objective-C. But don’t. Which reminds me: try to avoid #define
: it is
evil in 4 different ways: evil#1, evil#2,
evil#3, and evil#4.
There are places where pointer casts and unions are necessary and even wholesome, but they should be used carefully and sparingly. A pointer cast tells the compiler to believe you. An incorrect pointer cast might corrupt your heap, scribble into memory owned by other objects, call nonexistent member functions, and cause general failures. It’s not a pretty sight. If you avoid these and related constructs, you can make your C++ code both safer and faster, since anything that can be checked at compile time is something that doesn’t have to be done at run-time.
If you’re interested in using a pointer cast, use the new style pointer casts. The most common example of these is to
change old-style pointer casts such as (X*)p
into new-style dynamic casts such as dynamic_cast<X*>(p)
, where p
is a pointer and X
is a type. In addition to dynamic_cast
, there is static_cast
and const_cast
, but
dynamic_cast
is the one that simulates most of the advantages of dynamic typing (the other is the typeid()
construct; for example, typeid(*p).name()
will return the name of the type of *p
).
How do you use inheritance in C++, and is that different from Objective-C?
Some people believe that the purpose of inheritance is code reuse. In C++, this is wrong. Stated plainly, “inheritance is not for code reuse.”
The purpose of inheritance in C++ is to express interface compliance (subtyping), not to get code reuse. In C++, code reuse usually comes via composition rather than via inheritance. In other words, inheritance is mainly a specification technique rather than an implementation technique.
This is a major difference with Objective-C, where there is only one form of inheritance (C++ provides private
inheritance to mean “share the code but don’t conform to the interface”, and public
inheritance to mean “kind-of”).
The Objective-C language proper (as opposed to coding practice) allows you to have the effect of “hiding” an
inherited method by providing an override that calls the “does not understand” method. Furthermore Objective-C allows a
conceptual “is-a” relationship to exist apart from the inheritance hierarchy (subtypes don’t have to be derived
classes; e.g., you can make something that is-a Stack
yet doesn’t inherit from class
Stack
).
In contrast, C++ is more restrictive about inheritance: there’s no way to make a “conceptual is-a” relationship without using inheritance (the C++ work-around is to separate interface from implementation via ABCs). The C++ compiler exploits the added semantic information associated with public inheritance to provide static typing.
What are the practical consequences of differences in Objective-C/C++ inheritance?
[For context, please read the previous FAQ].
Objective-C lets you make a subtype that isn’t a derived class, and allows you to make a derived class that isn’t a
subtype. This allows Objective-C programmers to be very carefree in putting data (bits, representation, data structure)
into a class (e.g., you might put a linked list into class
Stack
). After all, if someone wants an
array-based-Stack
, they don’t have to inherit from Stack
; they could inherit such a class from Array
if desired,
even though an ArrayBasedStack
is not a kind-of Array
!
In C++, you can’t be nearly as carefree. Only mechanism (member function code), but not representation (data bits) can be overridden in derived classes. Therefore you’re usually better off not putting the data structure in a class. This leads to a stronger reliance on abstract base classes.
I like to think of the difference between an ATV and a Maserati. An ATV (all terrain vehicle) is more fun, since you can “play around” by driving through fields, streams, sidewalks, and the like. A Maserati, on the other hand, gets you there faster, but it forces you to stay on the road. My advice to C++ programmers is simple: stay on the road. Even if you’re one of those people who like the “expressive freedom” to drive through the bushes, don’t do it in C++; it’s not a good fit.