Search

9.2 — Overloading the arithmetic operators using friend functions

Some of the most commonly used operators in C++ are the arithmetic operators -- that is, the plus operator (+), minus operator (-), multiplication operator (*), and division operator (/). Note that all of the arithmetic operators are binary operators -- meaning they take two operands -- one on each side of the operator. All four of these operators are overloaded in the exact same way.

It turns out that there are three different ways to overload operators: the member function way, the friend function way, and the normal function way. In this lesson, we’ll cover the friend function way (because it’s more intuitive for most binary operators). Next lesson, we’ll discuss the normal function way. Finally, in a later lesson in this chapter, we’ll cover the member function way. And, of course, we’ll also summarize when to use each in more detail.

Overloading operators using friend functions

Consider the following trivial class:

The following example shows how to overload operator plus (+) in order to add two “Cents” objects together:

This produces the result:

I have 14 cents.

Overloading the plus operator (+) is as simple as declaring a function named operator+, giving it two parameters of the type of the operands we want to add, picking an appropriate return type, and then writing the function.

In the case of our Cents object, implementing our operator+() function is very simple. First, the parameter types: in this version of operator+, we are going to add two Cents objects together, so our function will take two objects of type Cents. Second, the return type: our operator+ is going to return a result of type Cents, so that’s our return type.

Finally, implementation: to add two Cents objects together, we really need to add the m_cents member from each Cents object. Because our overloaded operator+() function is a friend of the class, we can access the m_cents member of our parameters directly. Also, because m_cents is an integer, and C++ knows how to add integers together using the built-in version of the plus operator that works with integer operands, we can simply use the + operator to do the adding.

Overloading the subtraction operator (-) is simple as well:

Overloading the multiplication operator (*) and division operator (/) are as easy as defining functions for operator* and operator/.

Friend functions can be defined inside the class

Even though friend functions are not members of the class, they can still be defined inside the class if desired:

We generally don’t recommend this, as non-trivial function definitions are better kept in a separate .cpp file, outside of the class definition. However, we will use this pattern in future tutorials to keep the examples concise.

Overloading operators for operands of different types

Often it is the case that you want your overloaded operators to work with operands that are different types. For example, if we have Cents(4), we may want to add the integer 6 to this to produce the result Cents(10).

When C++ evaluates the expression x + y, x becomes the first parameter, and y becomes the second parameter. When x and y have the same type, it does not matter if you add x + y or y + x -- either way, the same version of operator+ gets called. However, when the operands have different types, x + y is not the same as y + x.

For example, Cents(4) + 6 would call operator+(Cents, int), and 6 + Cents(4) would call operator+(int, Cents). Consequently, whenever we overload binary operators for operands of different types, we actually need to write two functions -- one for each case. Here is an example of that:

Note that both overloaded functions have the same implementation -- that’s because they do the same thing, they just take their parameters in a different order.

Another example

Let’s take a look at another example:

The MinMax class keeps track of the minimum and maximum values that it has seen so far. We have overloaded the + operator 3 times, so that we can add two MinMax objects together, or add integers to MinMax objects.

This example produces the result:

Result: (3, 16)

which you will note is the minimum and maximum values that we added to mFinal.

Let’s talk a little bit more about how “MinMax mFinal = m1 + m2 + 5 + 8 + m3 + 16” evaluates. Remember that operator+ has higher precedence than operator=, and operator+ evaluates from left to right, so m1 + m2 evaluate first. This becomes a call to operator+(m1, m2), which produces the return value MinMax(8, 15). Then MinMax(8, 15) + 5 evaluates next. This becomes a call to operator+(MinMax(8, 15), 5), which produces return value MinMax(5, 15). Then MinMax(5, 15) + 8 evaluates in the same way to produce MinMax(5, 15). Then MinMax(5, 15) + m3 evaluates to produce MinMax(3, 15). And finally, MinMax(3, 15) + 16 evaluates to MinMax(3, 16). This final result is then assigned to mFinal.

In other words, this expression evaluates as “MinMax mFinal = (((((m1 + m2) + 5) + 8) + m3) + 16)”, with each successive operation returning a MinMax object that becomes the left-hand operand for the following operator.

One other interesting thing to note is that we defined operator+(int, MinMax) by calling operator+(MinMax, int). This may be slightly less efficient than implementing it directly (due to the extra function call, assuming your compiler can’t optimize the function call away), but keeps our code shorter and easier to maintain because it reduces duplicate code. It is often possible to define overloaded operators by calling other overloaded operators -- when possible, do so!

Quiz time

1a) Write a class named Fraction that has a integer numerator and denominator member. Write a print() function that prints out the fraction.

The following code should compile:

This should print:

1/4
1/2

Show Solution

1b) Add overloaded multiplication operators to handle multiplication between a Fraction and integer, and between two Fractions. Use the friend function method.

Hint: To multiply two fractions, first multiply the two numerators together, and then multiply the two denominators together. To multiply a fraction and an integer, multiply the numerator of the fraction by the integer and leave the denominator alone.

The following code should compile:

This should print:

2/5
3/8
6/40
4/5
6/8
6/24

Show Solution

1c) Extra credit: the fraction 2/4 is the same as 1/2, but 2/4 is not reduced to the lowest terms. We can reduce any given fraction to lowest terms by finding the greatest common divisor (GCD) between the numerator and denominator, and then dividing both the numerator and denominator by the GCD.

The following is a function to find the GCD:

Add this function to your class, and write a member function named reduce() that reduces your fraction. Make sure all fractions are properly reduced.

The following should compile:

And produce the result:

2/5
3/8
3/20
4/5
3/4
1/4

Show Solution

9.2a -- Overloading operators using normal functions
Index
9.1 -- Introduction to operator overloading

161 comments to 9.2 — Overloading the arithmetic operators using friend functions

  • Donlod

    Quick question:
    1. Why doesnt this work?

    Either i have to add this->gcd(...) or i have to make the variable a different name.

    2. What is in this case best practice with the gcd function regarding static/non-static and private/public?

    • nascardriver

      Hi Donlod!

      1. That's the result of a poor naming convention. "gcd" occurs twice but naming different entities. Your compiler can't differentiate between the two.

      2. Ideally @gcd shouldn't be a part of @Fraction but rather a part of a more general mathematical class or namespace. If it's in @Fraction, I'd go for private static.

  • radu f

    Regarding the extra credit problem, shouldn't be gcd(int, int) and reduce() be private members of the class Fraction? I think, normally, the user don't need access to them in these circumstances, right?
    Well, I manage to solve the quizz, but in a not so efficient manner:
    - it didn't cross my mind to put reduce() in the constructor, I used instead the following:

    paired with:

    Not sure how it looks concerning the memory usage [the anonymous object returned by reduce() looks like an unwelcome guest to a party to me now ...].

    Fraction.cpp:

    Fraction.h

    • nascardriver

      Hi radu!

      > shouldn't be gcd(int, int) and reduce() be private members of the class Fraction?
      If you don't intend them being used outside the class you should declare them private (or protected).

      > Not sure how it looks concerning the memory usage
      Bad. You're creating two @Fraction objects although you only need one in the end.
      This problem can be solved by having @reduce modify the object it's called on rather than creating a new @Fraction and returning itself by reference or pointer.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]