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 2 of 4 of this article. Click here to view the first page.

Implementing Class Member Functions

You’ve seen how to define a class interface, but what about the functions? That’s quite simple, as it turns out. There’s a couple of ways you can do it.

The first way to implement a method is by defining it in the class’s implementation file — the .cpp file. You would do this as follows:

// MyClass.h
class MyClass {
    int x;
    int y;
    void foo();
};

// MyClass.cpp
#include “MyClass.h”

MyClass::foo() {
   // Do something
}

That’s the first way; it’s very similar to how you would do it in Objective-C. Notice the use of MyClass::; this is how you denote that the foo() function is being implemented as part of the MyClass class.

The second way to implement a method is something you can’t do in Objective-C. In C++ you can implement a method directly in the header file, like so:

// MyClass.h
class MyClass {
    int x;
    int y;
    void foo() {
        // Do something
    }
};

This might look quite odd to you if you’ve only ever used Objective-C. It is quite odd, but it can also be quite useful. When a function is declared in this way, the compiler can perform an optimisation called “inlining”. This means that when this function is called, instead of jumping to a new block of code, the entire function code is compiled inline at the call site.

While inlining can make code faster, it also increases the size of the compiled code because if the function is called more than once, the code will duplicated throughout the binary. If the function is quite large, or called a lot of times, then this can have a significant impact on the size of the binaries. This can cause a performance decrease because less code can fit in the cache, meaning there may be potentially more cache misses.

My goal here is to illustrate that C++ allows a lot of flexibility. It’s up to you as a developer to understand the trade-offs and make decisions based on this. Of course, the only way to really know which choice is right for you is to instrument your code!

pic1

Namespaces

The example you saw above introduced some new syntax that you haven’t encountered before — the double colon – ::. This is how you reference scope within C++; it’s used above to tell the compiler where it should look for the foo function.

Another time you’ll see the double colon is when using namespaces. Namespaces are a way to separate code so that naming clashes are less likely to occur.

For example, you might implement a class called Person in your own code, but a third party library may also implement a class called Person. Therefore, when writing C++ you will usually put all your code into a namespace to avoid these types of naming collisions.

It’s easy to do this; you just wrap everything with the following namespace declarations:

namespace MyNamespace {
    class Person { … };
}

namespace LibraryNamespace {
    class Person { … };
}

Now, when using either implementation of the Person class, you can disambiguate using the double colon, like so:

MyNamespace::Person pOne;
LibraryNamespace::Person pTwo;

Simple, isn’t it?

There is no equivalent to namespaces in Objective-C, other than by the convention of placing a prefix on your classes…you do name your classes like this, right? ;] Well if you don’t, then this is a perfect reason to start doing it straight away!

Note: There have been a few proposals for namespaces in Objective-C. One such proposal can be found here. I don’t know if we’ll ever see them in Objective-C, but I sure hope so myself!

Memory Management

Oh no… not that dreaded phrase! Memory management is one of the most important things to understand in any language. Java basically lets the garbage collector do its job. Objective-C requires that you understand reference counting and the role that ARC plays. In C++… well, C++ is a different beast once again.

First of all, to understand memory management in C++ you really need to understand the stack versus the heap. Even if you think you know about this, I suggest you carry on reading anyway; you’ll probably learn a thing or two.

  • The stack is a block of memory available to a running application. It’s a fixed size and is used by the application’s code to store data. The stack works on a push/pop basis; when a given function runs it pushes data onto the stack, and when a function finishes, it must pop off the same amount of data. Therefore, over time the stack usage will not grow.
  • The heap is also a block of memory available to a running application. It is not of any fixed size, and grows as the application runs. This is where applications tend to store data that’s used outside of a function’s scope. Also, large sets of data will usually be stored in the heap because storing it on the stack may overflow the stack — remember, the stack is a fixed size.

That’s a very brief overview of stack and heap theory; here’s some C code that shows the two in action:

int stackInt = 5;
int *heapInt = malloc(sizeof(int));
*heapInt = 5;
free(heapInt);

Here, stackInt is using stack space; after the function returns, the memory being used to store the value “5” is automatically freed.

Hoever, heapInt is using heap space. The call to malloc allocates enough space on the heap to store an int. But because heap has to be managed by you, the developer, there needs to be a call to free after you’ve finished with the data to ensure you’re not leaking memory.

In Objective-C, you can only create objects on the heap; you’ll receive a compiler error if you try to create an object on the stack. It simply won’t work.

Consider the following example:

NSString stackString;
// Untitled 32.m:5:18: error: interface type cannot be statically allocated
//         NSString stackString;
//                  ^
//                  *
// 1 error generated.

That’s why you see asterisks all over Objective-C code; all objects are created on the heap and you have pointers to those objects. This largely comes down to the way that Objective-C handles memory management. Reference counting is very much baked-in to Objective-C; objects need to be on the heap so that their lifetime can be tightly controlled.

In C++ you can decide to either store data on the stack or the heap; the choice is up to you as a developer. However, in C++ you also have to manage the memory all by yourself. Putting data on the stack is taken care of automatically, but when you start using the heap you have to handle the memory management yourself — or risk springing leaks all over the place.

Contributors

Over 300 content creators. Join our team.