Navigation



9.2 — Overloading the arithmetic operators

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.

Overloading operators using friend functions

When the operator does not modify its operands, the best way to overload the operator is via friend function. None of the arithmetic operators modify their operands (they just produce and return a result), so we will utilize the friend function overloaded operator method here.

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

class Cents
{
private:
    int m_nCents;

public:
    Cents(int nCents) { m_nCents = nCents; }

    // Add Cents + Cents
    friend Cents operator+(const Cents &c1, const Cents &c2);

    int GetCents() { return m_nCents; }
};

// note: this function is not a member function!
Cents operator+(const Cents &c1, const Cents &c2)
{
    // use the Cents constructor and operator+(int, int)
    return Cents(c1.m_nCents + c2.m_nCents);
}

int main()
{
    Cents cCents1(6);
    Cents cCents2(8);
    Cents cCentsSum = cCents1 + cCents2;
    std::cout << "I have " << cCentsSum .GetCents() << " cents." << std::endl;

    return 0;
}

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_nCents member from each Cents object. Because our overloaded operator+() function is a friend of the class, we can access the m_nCents member of our parameters directly. Also, because m_nCents 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:

class Cents
{
private:
    int m_nCents;

public:
    Cents(int nCents) { m_nCents = nCents; }

    // overload Cents + Cents
    friend Cents operator+(const Cents &c1, const Cents &c2);

    // overload Cents - Cents
    friend Cents operator-(const Cents &c1, const Cents &c2);

    int GetCents() { return m_nCents; }
};

// note: this function is not a member function!
Cents operator+(const Cents &c1, const Cents &c2)
{
    // use the Cents constructor and operator+(int, int)
    return Cents(c1.m_nCents + c2.m_nCents);
}

// note: this function is not a member function!
Cents operator-(const Cents &c1, const Cents &c2)
{
    // use the Cents constructor and operator-(int, int)
    return Cents(c1.m_nCents - c2.m_nCents);
}

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

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:

class Cents
{
private:
    int m_nCents;

public:
    Cents(int nCents) { m_nCents = nCents; }

    // Overload cCents + int
    friend Cents operator+(const Cents &cCents, int nCents);

    // Overload int + cCents
    friend Cents operator+(int nCents, const Cents &cCents);

    int GetCents() { return m_nCents; }
};

// note: this function is not a member function!
Cents operator+(const Cents &cCents, int nCents)
{
    return Cents(cCents.m_nCents + nCents);
}

// note: this function is not a member function!
Cents operator+(int nCents, const Cents &cCents)
{
    return Cents(cCents.m_nCents + nCents);
}

int main()
{
    Cents c1 = Cents(4) + 6;
    Cents c2 = 6 + Cents(4);
    std::cout << "I have " << c1.GetCents() << " cents." << std::endl;
    std::cout << "I have " << c2.GetCents() << " cents." << std::endl;

    return 0;
}

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:

class MinMax
{
private:
    int m_nMin; // The min value seen so far
    int m_nMax; // The max value seen so far

public:
    MinMax(int nMin, int nMax)
    {
        m_nMin = nMin;
        m_nMax = nMax;
    }

    int GetMin() { return m_nMin; }
    int GetMax() { return m_nMax; }

    friend MinMax operator+(const MinMax &cM1, const MinMax &cM2);
    friend MinMax operator+(const MinMax &cM, int nValue);
    friend MinMax operator+(int nValue, const MinMax &cM);
};

MinMax operator+(const MinMax &cM1, const MinMax &cM2)
{
    // Get the minimum value seen in cM1 and cM2
    int nMin = cM1.m_nMin < cM2.m_nMin ? cM1.m_nMin : cM2.m_nMin;

    // Get the maximum value seen in cM1 and cM2
    int nMax = cM1.m_nMax > cM2.m_nMax ? cM1.m_nMax : cM2.m_nMax;

    return MinMax(nMin, nMax);
}

MinMax operator+(const MinMax &cM, int nValue)
{
    // Get the minimum value seen in cM and nValue
    int nMin = cM.m_nMin < nValue ? cM.m_nMin : nValue;

    // Get the maximum value seen in cM and nValue
    int nMax = cM.m_nMax > nValue ? cM.m_nMax : nValue;

    return MinMax(nMin, nMax);
}

MinMax operator+(int nValue, const MinMax &cM)
{
    // call operator+(MinMax, nValue)
    return (cM + nValue);
}

int main()
{
    MinMax cM1(10, 15);
    MinMax cM2(8, 11);
    MinMax cM3(3, 12);

    MinMax cMFinal = cM1 + cM2 + 5 + 8 + cM3 + 16;

    std::cout << "Result: (" << cMFinal.GetMin() << ", " <<
        cMFinal.GetMax() << ")" << std::endl;

    return 0;
}

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 cMFinal.

One other interesting thing to note is that we defined operator+(int, MinMax) by calling operator+(MinMax, int). This is slightly less efficient than implementing it directly (due to the extra function call), 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!

9.3 — Overloading the I/O operators
Index
9.1 — Introduction to operator overloading

35 comments to 9.2 — Overloading the arithmetic operators

  • [...] 9.2 — Overloading the arithmetic operators Category Indexes [...]

  • [...] — Overloading operators using member functions By Alex In the lesson on overloading the arithmetic operators, you learned that when the operator does not modify it’s operands, it’s best to [...]

  • Tom

    Hello Alex -

    A. Two typos:

    1. “When the operator does not modify its operands”

    2. “Finally, implementation: to add two Cents objects together”

    B. If instead of:

    MinMax cM2(8, 11);

    we had:

    MinMax cM2(25, 2);

    that would break the logic of the code (it would still return 3,16 instead of 2,25). How would you handle it? Like this maybe?:

    public:
         MinMax(int nMin, int nMax)
         {
             m_nMin = nMin < nMax ? nMin : nMax;
             m_nMax = nMax > nMin ? nMax : nMin;
         }
    
    • Thanks for the edits. As for point B, that’s actually an interesting concern. If possible, it’s always a good idea to think about how the user might misuse a class — and if there’s a reasonable way to handle it, then do so. In this case, your suggestion is perfect — if the user passes in the min and max in the wrong order to the constructor, we can detect that and flip them.

  • [...] 2007 Prev/Next Posts « 8.13 — Friend functions and classes | Home | 9.2 — Overloading the arithmetic operators » Monday, September 24th, 2007 at 2:23 [...]

  • minwei

    Hi, can demostrate a example for me on how(1,2,3,4) + (2,3,4,5) using operator overloading. I dun reali understand the example given

  • Kinten

    Hi alex, I have a dobout when you call

     Cents cCentsSum = cCents1 + cCents2; 

    you actually create a Cents object in the “cCents1 + cCents2″ part and then it is copied to cCentsSum, however in the case that you allocate a dinamic variable whit new, when you call the “cCents1 + cCents2″ part, the object will never go out of scope, and you will have a memory leak, I am right?

    Another thing, when you do the

    Cents cCentsSum = cCents1 + cCents2

    part, its the = operator always overloaded to copy every member variable of a class?

    Tnx, -Kin-

    • Yes, objects declared with new have to be deleted, otherwise the memory is lost and you have a memory leak. In this case, since we aren’t using new, that isn’t an issue we have to worry about.

      The compiler supplies every class with a default implementation of operator=, which copies each member variable.

  • M.N. Jayaram

    Hi

    I copied the code for Cents class example (the second one with two overloaded + operators) & the MinMax class to the clipboard & pasted it to my Code::Blocks IDE.

    The compiler flags the “No match for operator+ …..” error in lines 32 and 33 of the Cents example & line 56 in the MinMax example.

    Both the examples run successfully when the reference is removed i.e. pass by value as below

    friend Cents operator+(Cents cCents, int nCents);
    friend Cents operator+(int nCents, Cents cCents);

    friend MinMax operator+(MinMax cM1, MinMax cM2);
    friend MinMax operator+(MinMax cM, int nValue);
    friend MinMax operator+(int nValue, MinMax cM);

    What could be the reason ?

    P.S. : The example code runs as is in Visual C++ 6.0 without the above mentioned changes that I had to do to get Code::Blocks to run the example.

    • I believe it has to do with the way the different compilers handle references to intermediary objects. I fixed up the example by making all the reference parameters const references, as they should have been in the first place. I think it should work without error now.

  • M.N. Jayaram

    Hi

    I have an observation. Instead of having many versions of overloading the operators with different combos it should be sufficient to have one version of operator to do Objects & use type conversion to handle other types. Otherwise the no. of combos of operators may become too unwieldy.

    Thus, the Cents & MinMax examples work with minimal operator versions as below.

    // =============================
    class Cents
    {
    private:
        int m_nCents;
    
    public:
        // Acts as default constructor, parameterised constructor
        // Also performs type conversion from int to Cents
    
        Cents(int nCents) { m_nCents = nCents; }
    
        // overload Cents + Cents
        friend Cents operator+(const Cents &c1, const Cents &c2);
        int GetCents() { return m_nCents; }
    };
    
    // note: this function is not a member function!
    Cents operator+(const Cents &c1, const Cents &c2)
    {
        // use the Cents constructor and operator+(int, int)
        return Cents(c1.m_nCents + c2.m_nCents);
    }
    
    int main()
    {
        Cents c1 = Cents(4) + 6;
        Cents c2 = 6 + Cents(4);
        std::cout << "I have " << c1.GetCents() << " cents." << std::endl;
        std::cout << "I have " << c2.GetCents() << " cents." << std::endl;
        return 0;
    }
    
    // ======================================================
    
    class MinMax
    {
    private:
        int m_nMin; // The min value seen so far
        int m_nMax; // The max value seen so far
    
    public:
        MinMax(int nMin, int nMax)
        {
            m_nMin = nMin;
            m_nMax = nMax;
        }
    
        // Single argument Constructor which also doubles as
        // type converter from
    
        MinMax(int nMinMax)
        {
            m_nMin = nMinMax;
            m_nMax = nMinMax;
        }
        int GetMin() { return m_nMin; }
        int GetMax() { return m_nMax; }
    
        friend MinMax operator+(const MinMax &cM1, const MinMax &cM2);
    
    };
    
    MinMax operator+(const MinMax &cM1, const MinMax &cM2)
    {
        // Get the minimum value seen in cM1 and cM2
        int nMin = cM1.m_nMin < cM2.m_nMin ? cM1.m_nMin : cM2.m_nMin;
    
        // Get the maximum value seen in cM1 and cM2
        int nMax = cM1.m_nMax > cM2.m_nMax ? cM1.m_nMax : cM2.m_nMax;
    
        return MinMax(nMin, nMax);
    }
    
    int main()
    {
        MinMax cM1(10, 15);
        MinMax cM2(8, 11);
        MinMax cM3(3, 12);
    
        MinMax cMFinal = cM1 + cM2 + 5 + 8 + cM3 + 16;
    
        std::cout << "Result: (" << cMFinal.GetMin() << ", " <<
            cMFinal.GetMax() << ")" << std::endl;
    
        return 0;
    }
    // =========================================================
    
    • This is true, and is a great observation. The one major downside of doing it this way is that it is about half as efficient since you have to do the extra step of converting to a temporary object before producing your final result. Whether efficiency or additional maintainability is a larger concern depends on the nature of the class and project. Never-the-less, thanks for the great point.

    • Miguel

      Hi all,

      Note that the code above does not work when the programmer use template class instead (cf. http://www.learncpp.com/cpp-tutorial/143-template-classes for deatils):

      #include <iostream>
      
      template < typename T > class Cents
      {
        private:
          T m_nCents;
      
        public:
          // Acts as default constructor, parameterised constructor
          // Also performs type conversion from int to Cents
      
          Cents < T > (int nCents)
          {
              m_nCents = nCents;
          }
      
          // overload Cents + Cents
          template < typename X > friend Cents < X > operator+(const Cents < X > &c1,
                                                               const Cents < X > &c2);
          T       GetCents()
          {
              return m_nCents;
          }
      };
      
      // note: this function is not a member function!
      template < typename T > Cents < T > operator+(const Cents < T > &c1, const Cents < T > &c2)
      {
          // use the Cents constructor and operator+(int, int)
          return Cents<T>(c1.m_nCents + c2.m_nCents);
      }
      
      int main()
      {
          Cents < int >c1 = Cents < int >(4) + 6;
          Cents < int >c2 = 6 + Cents < int >(4);
      
          std::cout << "I have " << c1.GetCents() << " cents." << std::endl;
          std::cout << "I have " << c2.GetCents() << " cents." << std::endl;
          return 0;
      }
      

      This code makes the g++ compiler complaining about operator+ :

      cents.cpp:35: erreur: no match pour « operator+ » dans « Cents<int>(4) + 6 »
      cents.cpp:36: erreur: no match pour « operator+ » dans « 6 + Cents<int>(4) »
      

      The programmer shall explicitly define the operator+ (as Alex has done in its example).

      The Jayaram suggestion is nice, but it implies some magics from compiler.

      The advantage that I see from the Alex code sample is that there is no magic, making code clearer and allow the programmer changing a non template class into template class without surprise :)

    • Matt

      I don’t understand how your code works with respect to the addition at the end. To me it looks like that single parameter Minmax would handle the ints so it would treat them like a class where both the min and the max were the same value. I never see a function call to that though so how does your program know how to treat the addition (no pun intended) of intends along with that of classes?

  • Jay

    You might want to explain why the operators should be a friend function instead of a member function and therefore breaking encapsulation.

  • Lucky

    Hi Alex,
    I am really confused with this operator overloading concept. Especially I dont understand y shoul
    d we use a friend class. In the example discussed above

    // note: this function is not a member function!
    Cents operator+(Cents &c1, Cents &c2)
    {
    // use the Cents constructor and operator+(int, int)
    return Cents(c1.m_nCents + c2.m_nCents);
    }

    A.Y r we using call by reference??
    B.What happens in Main when

    Cents cCentsSum = cCents1 + cCents2;

    is encountered/

    • A lot of times we use friend classes when doing operator overloading because it makes the functions easier to write.

      Remember that a member function always has to have an implicit data type that is pointed to by *this. Thus, if you do something like this:

      a + b

      , the compiler translates that to a.add(b). a becomes the implicit data type. Now we have a as an implicit type, and b as an explicit type. This can be awkward.

      However, if we use a friend function, then both a and b come through as parameters, which makes the functions easier to write because we don’t have to worry about any implicit variables.

      In this case, we use call by reference because we don’t want to copy the Cents class to do a pass-by-value. Really, those should be const references.

      • Hi Alex, Is it still good coding if we just have the operators as member functions, I’ve only started and it appears easier for me to have everything inside the class.

        Also in light of using friend functions and manageability where do you recommend I keep them (the friend functions). Just below my class, like your example, or somewhere else?

        Cheers,

  • mahen

    Hi Alex,
    In the first example in this page… u passed the cents objets by reference …since they are objects, arent they passed by reference implicitly?…… y did u explicitly pass them by reference ?….

  • [...] 9.2 Overloading the arithmetic operators [...]

  • thabukkow

    Why do you use a reference as a parameter:

    MinMax operator+(const MinMax &cM1, const MinMax &cM2)

    it works the same when I use this:

    MinMax operator+(const MinMax cM1, const MinMax cM2)

    I also changed the declaration of the friend function

  • Dominator_X

    friend MinMax operator+(const MinMax &cM1, const MinMax &cM2);

    What does &cM1? Please reply! Can you explain in more detail.

  • mccp13

    Hey Alex,
    Thanks for the tutorials…. I have a question though about the following code. This code compiles properly but i’m wondering why the compiler did not issue an error message when cent2.m_nCents was accessed in the overloaded member function operator+ of myCent1 in main, if the member was private. :

    class Cents
    {
    private:
    m_nCents;
    public:
    //Constructor
    Cents( int nCents ) { m_nCents = nCents; }
    int GetCents(){ return m_nCents; }

    Cents operator+( const Cents& cent2 )
    {
    return Cents( this->m_nCents + cent2.m_nCents );
    }
    };

    int main()
    {
    using namespace std;
    Cents myCent1(6);
    Cents myCent2(8);
    Cents myCent3( myCent1 + myCent2 );
    cout << myCent3.GetCents() << endl;

    return EXIT_SUCCESS;
    }

    btw, i learned this in some OOP book…

  • [...] starts to make sense.  Lesson learned: don’t code when brain-dead.  #superobvious  Overloading the arithmetic operators « Learn C++. Share this:TwitterFacebookLike this:Like Loading… This entry was posted in C++ by naptunian. [...]

  • [...] new to overloading operators, I did some search and found this helpful article, I wrote my own code like the author did but I get vector vector::operator*(float, vector) must [...]

  • [...] Overloading the comparison operators is simple once you’ve learned how to overload the arithmetic operators. [...]

  • [...] the lesson on overloading the arithmetic operators, you learned that when the operator does not modify it’s operands, it’s best to implement the [...]

  • dibhar

    Hi Alex,

    Thanks a lot for the tutorials…:)

    having a doubt-

    in the code below if i just remove the keyword friend from the operator function i am getting compilation error :operator+ must take either 0 or 1 argument…why??though we have declared it with two argument…

    #include
    #include
    class Cents
    {
    private:
    int m_nCents;

    public:
    Cents(int nCents) { m_nCents = nCents; }

    // Add Cents + Cents
    Cents operator+(const Cents &c1, const Cents &c2); /*I have removed friend from here*/

    int GetCents() { return m_nCents; }
    };

    // note: this function is not a member function!
    Cents::Cents operator+(const Cents &c1, const Cents &c2)
    {
    // use the Cents constructor and operator+(int, int)
    return Cents(c1.m_nCents + c2.m_nCents);
    }

    int main()
    {
    Cents cCents1(6);
    Cents cCents2(8);
    Cents cCentsSum = 4+3+cCents1 + cCents2+5;
    std::cout << "I have " << cCentsSum .GetCents() << " cents." << std::endl;
    getch();
    return 0;
    }

  • pardeep

    thank you very much sir…..
    this site is very helpful to me.

  • akshath

    Learncpp articles were very helpful to me while learning c++.
    In this section why the overloaded artihmetic operators should nor return a reference to the object of class type?I believe lvalues can be assigned to lvalues by implicit conversion to rvalues.thank you

  • [...] this article the author chose the return type to be class type http://www.learncpp.com/cpp-tutorial/92-overloading-the-arithmetic-operators/emphasized text ,Can we just change the return type to return int, because i wanted to do the [...]

You must be logged in to post a comment.