C++ Tutorials
Arithmetic Operators
This post is part of a series of tutorials on C++
Arithmetic operators allow you to perform basic expressions with instances of C++ objects, such as addition, and subtraction. These can be useful in a variety of settings, in particular when your C++ classes have natural definitions that you’d like to use and chain together.
Let’s focus first on binary arithmetic operators. Most every C++ operator that comes in the form A = B # C
can be overloaded, where #
is a placeholder for the operator in question. One possible signature for such operators, using addition (+
) as an example, is:
You might at first think this is OK (and it is). We’ve appropriately using a const reference to pass in the input, since we have no intention of changing rhs
, and we will then add it to our current member, without changing it. We then create a new object, ret
that is there sum and return it by copy. In practice, when executing your code you would do something like this:
The line c = a + b
is deceptively complex. a+b
translates to a.operator+(b)
which then returns a copy of an object and then c = ...
calls the assignment operator to copy this object into c. That’s quite a lot of work, it turns out. While this is all valid C++ code, the thing to remember is that you’re overloading a function, which means that there can be many valid signatures. Consider the following:
Which might seem far fetched! Why would we want to add a int
to a Foo
? Well, let’s give a more concrete example:
In the above example, RationalNumber
stores a fraction, \(\frac{\textrm{num}}{\textrm{denom}}\) without using floating point values. If one wants to add another integer value, rhs
to this fraction, one then adds rhs
copies of the denominator, denom
.
We can then right expressions like:
Which is kind of handy. Since operators can be overloaded, we can do all sorts of interesting things with them! Unfortunately, with the above code, we run into a nasty issue:
The above code fails to compile because of how operators are expanded. 5 + a
is equivalent to 5.operator+(a)
, but 5 is a literal, not an instance of a class. It has no member functions can of course we can’t using the .
operator on it. The solution is, unfortunately, kind of crude:
We’re forced to use friend
functions. In C++, the friend
keyword allows a non-member function to access class members. Note that while the first operator+()
is defined as a class member, and thus has the class scoping RationalNumber::
, the second operator+()
is just defined as a standalone function (and thus, for example, cannot access this
). It’s not horrible, but the duality between the two is suboptimal. Still, in this case we’re defining an asymmetric version of +
, since the types of the lhs
and rhs
are not the same. For our purposes, the major instance where you might consider doing things this way is to scale a three-dimensional vector by a scalar. Nevertheless, if you don’t want to code the friend function, you can always just make sure that you multiply by scalars on the right, but that’s not quite as user friendly.
See Arithmetic Operators, Part 2 for more info.