Introduction to C++ for iOS Developers: Part 2

In part 2 of this introduction to C++ for iOS developers, you will learn about polymorphism, virtual functions, templates, the STL, and more. By Matt Galloway.

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

Operator overloading

This next topic doesn’t exist at all in Objective-C, so you might find the concept a little bit daunting at first. But fear not, it’s really not that complicated after all!

An operator are entities such as the familiar +, -, *, or /. For example, you would use the + operator with standard scalars as such:

int x = 5;
int y = x + 5; ///< y = 10

The + here is obvious in what it does: it adds x to 5 and returns the result. It might not be obvious, but this is effectively a function which could have been written like this:

int x = 5;
int y = add(x, 5);

In our imaginary function, add(…) adds the two parameters and returns the result.

In C++ it’s possible to define what happens when you use an operator on any of your own classes. This can be extremely powerful. Of course it doesn’t always make sense. What would it mean to add a Person to a Person for example? Maybe they become married!? :]

Nevertheless, this feature can be extremely useful. Consider the following class:

class DoubleInt {
  private:
    int x;
    int y;

  public:
    DoubleInt(int x, int y) : x(x), y(y) {}
};

It might be nice to be able to do this:

DoubleInt a(1, 2);
DoubleInt b(3, 4);
DoubleInt c = a + b;

We want c to be equivalent to DoubleInt(4, 6) here - i.e., add x and y of each DoubleInt instance together. This is simple, it turns out! All you need to do is add a method to DoubleInt that looks like this:

DoubleInt operator+(const DoubleInt &rhs) {
    return DoubleInt(x + rhs.x, y + rhs.y);
}

The function called operator+ is special; it's used whenever the compiler sees a DoubleInt on either side of a +. This function is called on the object on left hand side of the +, passing in the object on the right hand side as the parameter. That’s why the parameter is often named "rhs", standing for "right hand side".

The parameter to the function is a reference because taking a copy would be unnecessary and might alter the value, as it would be a new object being constructed. It’s also constant, because it’s illegal for the right hand side to change during the addition.

C++ can go even further than this. Maybe you don’t want to just add a DoubleInt to a DoubleInt. Maybe you want to be able to add an int to a DoubleInt. That’s possible as well!

To achieve this you would implement the following member function:

DoubleInt operator+(const int &rhs) {
    return DoubleInt(x + rhs, y + rhs);
}

Then you could do the following:

DoubleInt a(1, 2);
DoubleInt b = a + 10;
// b = DoubleInt(11, 12);

Super! And very powerful, I’m sure you’ll agree.

It doesn’t just stop at addition though. The same can be done with any operator. You can overload ++, --, +=, -=, *, ->, and many more. Going through all of them here would take far too long. I suggest if you want to read more about operator overloading then head on over to learncpp.com where there is a whole chapter dedicated to operator overloading.

Templates

Roll up your sleeves now. Here comes a rather interesting topic of C++.

How often have you written a function or a class and then found yourself writing the same function or class again — but with different types? As an example, consider a function to swap two values. You might write a function like this:

void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

Note: Notice the use of pass by reference here so that the values that are passed in will actually be swapped. If the values were passed by value then it would be the function’s own copy of the values that would be swapped. This is another good example of a function that benefits from C++’s reference feature.

That works only on integers. If you want this to work for floats, then you would need to write another function:

void swap(float &a, float &b) {
    float temp = a;
    a = b;
    b = temp;
}

It’s a bit silly that you’ve had to duplicate the body of the function. C++ introduces syntax that allows you to effectively ignore the type. You can accomplish this via a feature known as templates. Instead of writing the two methods above, in C++, you can write the following:

template <typename T>
void swap(T a, T b) {
    T temp = a;
    a = b;
    b = temp;
}

Then, when you use swap with any type whatsoever, your function will swap them! You could call your function in any of the following ways:

int ix = 1, iy = 2;
swap(ix, iy);

float fx = 3.141, iy = 2.901;
swap(fx, fy);

Person px(“Matt Galloway”), py(“Ray Wenderlich”);
swap(px, py);

You need to be careful with templates, though; this approach only works if the implementation for the template function is in a header file. This is due to the way templates are compiled. When the compiler sees a template function being used, it compiles a version for that type if one doesn’t already exist.

Given that the compiler needs to see the template function implementation, you need to put the implementation in a header file and include that everywhere you use it.

Similarly, if you edit the implementation of a template function, every other file that uses that function needs to be recompiled. This is in contrast to editing a function or class member function implemented in an implementation file; in that case, only the one file needs to be recompiled.

For this reason, extensive use of templates can make an application cumbersome. But their power is extremely useful, so like many things in C++, it's always a balancing act between power and simplicity.

Contributors

Over 300 content creators. Join our team.