Introduction to C++ for iOS Developers: Part 1

In part 1 of this introduction to C++ for iOS developers, you will learn about C++ syntax, inheritance, namespaces, memory management, and more. By Matt Galloway.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

C++ new and delete

C++ introduces a couple of keywords to help with memory management of heap objects; they’re used to create and destroy objects on the heap.

Creating an object is done like this:

Person *person = new Person();

When you are finished with the object, you can get rid of it like this:

delete person;

In fact, this even works for scalar types in C++:

int *x = new int();
*x = 5;
delete x;

You can think of these operations as equivalent to the initialization and destruction of objects in Objective-C. Initialization in C++, using new Person(), is equivalent to [[Person alloc] init] in Objective-C.

There is no specific equivalent to delete in Objective-C, though. As I’m sure you’re aware, deallocation of an Objective-C object is handled for you by the runtime when its retain count drops to zero. Remember, C++ doesn’t do reference counting for you. You’re in charge of deleting the object when you’ve finished with it.

You now have an overview of memory management in C++; the takeaway here is that it’s a lot more complex to manage memory in C++ than in Objective-C. You really need to think about what’s going on and keep track of all of your objects.

pic2

Accessing Members of Stack and Heap Objects

You’ve seen that objects can be created on either the stack or the heap in C++. However, there’s one subtle but important difference when using each type: the way you access member variables and member functions is slightly different.

When using stack objects, you need to use the dot operator (.). With heap objects, you need to dereference the pointer using the arrow operator (->), like so:

Person stackPerson;
stackPerson.name = “Bob Smith”; ///< Setting a member variable
stackPerson.doSomething(); ///< Calling a member function

Person *heapPerson = new Person();
heapPerson->name = “Bob Smith”; ///< Setting a member variable
heapPerson->doSomething(); ///< Calling a member function

The difference is subtle, but important to note.

You'll also see the arrow operator used with the this pointer; it's the same thing as the self pointer in Objective-C, and is used inside class member functions to access the current object.

The following C++ example shows the usage of the arrow operator:

Person::doSomething() {
    this->doSomethingElse();
}

This leads into a common gotcha with C++. In Objective-C, if you call a method on a nil pointer, your app will still run fine:

myPerson = nil;
[myPerson doSomething]; // does nothing

However, in C++ if you try to call a method or access an instance variable on a NULL pointer, your app will crash:

myPerson = NULL;
myPerson->doSomething(); // crash!

Therefore, you must be very careful in C++ to make sure you do not attempt to do work on NULL pointers.

References

When you pass an object to a function, you're passing a copy of the object, not the obejct itself. For example, consider the following block of C++ code:

void changeValue(int x) {
    x = 5;
}

// …

int x = 1;
changeValue(x);
// x still equals 1

This is pretty straightforward and comes as no surprise. But look what happens when you do the same thing with a function that takes an object as a parameter:

class Foo {
  public:
    int x;
};

void changeValue(Foo foo) {
    foo.x = 5;
}

// …

Foo foo;
foo.x = 1;
changeValue(foo);
// foo.x still equals 1

Maybe that’s a little more surprising to you. If you think about it, it’s no different from the simple int case. What’s happening is a copy of the Foo object is made before passing it to the function.

Sometimes, though, you do want to pass the actual object. One way to do it would be to change the function to take a pointer to the object, rather than the object itself. But then that adds extra code whenever you call the function.

C++ adds a new concept which allows you to pass a variable “by reference”. This means that no copy is made; this is in contrast to the above examples which demonstrates passing “by value”.

It’s simple to change your calls to pass by reference; you simply use the address operator by adding an ampersand (&) in front of the variable in the function signature, like so:

void changeValue(Foo &foo) {
    foo.x = 5;
}

// …

Foo foo;
foo.x = 1;
changeValue(foo);
// foo.x equals 5

It also works for non-class variables:

void changeValue(int &x) {
    x = 5;
}

// …

int x = 1;
changeValue(x);
// x equals 5

Pass by reference can be very useful and can significantly improve performance. This is particularly true if making a copy of an object is extremely expensive, such as working with a huge list where creating a copy means performing a deep copy on the object.

Inheritance

An object-oriented language just wouldn’t be complete without inheritance, and C++ certainly doesn’t buck this trend. Consider the following two Objective-C classes where one inherits from the other:

@interface Person : NSObject
@end

@interface Employee : Person
@end

The same thing can be expressed in C++, in a very similar way:

class Person {
};

class Employee : public Person {
};

The only difference in C++ is the addition of the public keyword. Here, Employee inherits publicly from Person. This means that all the public members of Person remain public in Employee.

If you replaced public with private, then the public members of Person would become private in Employee. For more information about this topic, I suggest reading through a great article about inheritance and access specifiers here.

That’s the easy part about inheritance — now comes the hard bit. C++ is different from Objective-C in that it allows multiple inheritance. This lets a class inherit from two or more base classes. That might seem alien to you, especially if you haven't used a language other than Objective-C.

Here is an example of multiple inheritance in C++:

class Player {
    void play();
};

class Manager {
    void manage();
};

class PlayerManager : public Player, public Manager {
};

In this example, there are two base classes and one class which inherits from both. This means that the PlayerManager has access to all of the member variables and functions of each base class. Neat, eh? As I’m sure you’re painfully aware, there is no way to do this in Objective-C.

Well...that’s not strictly true, is it?

The astute reader will notice that there is something similar in Objective-C: protocols. While not quite the same thing as multiple inheritance, both techniques aim to solve the same problem: providing a mechanism to link together classes that serve similar purposes.

Protocols are slightly different in that a protocol has no implementation; rather, it simply serves as a way to describe an interface to which a class must conform.

In Objective-C, the example above could be written as follows:

@protocol Player
- (void)play;
@end

@protocol Manager
- (void)manage;
@end

@interface Player : NSObject <Player>
@end

@interface Manager : NSObject <Manager>
@end

@interface PlayerManager : NSObject <Player, Manager>
@end

Of course, this is ever so slightly contrived, but you get the picture. In Objective-C you would have to implement both play and manage in the PlayerManager class, whereas in C++ you would just implement the method in each base class and then the PlayerManager class would automatically inherit each implementation.

In practice, though, multiple inheritance can sometimes lead to confusion and complication. It is often regarded among C++ developers as a dangerous tool to be avoided at all costs unless absolutely necessary.

Why? Consider what could happen if both base classes implemented a function with the same name and that accepted the same arguments — that is, both would have the same prototype. In this case, you'd need a way to disambiguate one from the other. For example, imagine both Player and Manager classes had a function named foo.

You would need to disambiguate like so:

PlayerManager p;
p.foo();          ///< Error! Which foo?
p.Player::foo();  ///< Call foo from Player
p.Manager::foo(); ///< Call foo from Manager

This is certainly doable, but it adds confusion and a layer of complexity which is best avoided. The decision is up to the user of PlayerManager. Using protocols leaves it up to the PlayerManager class to implement foo so that there's only one implementation — and zero confusion.

Contributors

Over 300 content creators. Join our team.