Search

9.4 — Overloading operators using member functions

In lesson 9.2 -- Overloading the arithmetic operators using friend functions, you learned how to overload the arithmetic operators using friend functions. Many operators can be overloaded in a second way: as a member function.

Overloading operators using a member function is very similar to overloading operators using a friend function. When overloading an operator using a member function:

  • The overloaded operator must be added as a member function of the left operand.
  • The left operand becomes the implicit *this object
  • All other operands become function parameters.

As a reminder, here’s how we overloaded operator+ using a friend function:

Converting a friend overloaded operator to a member overloaded operator is easy:

  1. The overloaded operator is defined as a member instead of a friend (Cents::operator+ instead of friend operator+)
  2. The left parameter is removed, because that parameter now becomes the implicit *this object.
  3. Inside the function body, all references to the left parameter can be removed (e.g. cents.m_cents becomes m_cents, which implicitly references the *this object).

Now, the same operator overloaded using the member function method:

Note that the usage of the operator does not change (in both cases, cents1 + 2), we’ve simply defined the function differently. Our two-parameter friend function becomes a one-parameter member function, with the leftmost parameter in the friend version (cents) becoming the implicit *this parameter in the member function version.

Let’s take a closer look at how the expression cents1 + 2 evaluates.

In the friend function version, the expression cents1 + 2 becomes function call operator+(cents1, 2). Note that there are two function parameters. This is straightforward.

In the member function version, the expression cents1 + 2 becomes function call cents1.operator+(2). Note that there is now only one explicit function parameter, and cents1 has become an object prefix. However, in lesson 8.8 -- The hidden “this” pointer, we mentioned that the compiler implicitly converts an object prefix into a hidden leftmost parameter named *this. So in actuality, cents1.operator+(2) becomes operator+(&cents1, 2), which is almost identical to the friend version.

Both cases produce the same result, just in slightly different ways.

So if we can overload an operator as a friend or a member, which should use use? In order to answer that question, there’s a few more things you’ll need to know.

Not everything can be overloaded as a friend function

The assignment (=), subscript ([]), function call (()), and member selection (->) operators must be overloaded as member functions, because the language requires them to be.

Not everything can be overloaded as a member function

In lesson 9.3 -- Overloading the I/O operators, we overloaded operator<< for our Point class using the friend function method. Here’s a reminder of how we did that:

However, we are not able to overloaded operator<< as a member function. Why not? Because the overloaded operator must be added as a member of the left operand. In this case, the left operand is an object of type std::ostream. std::ostream is fixed as part of the standard library. We can’t modify the class declaration to add the overload as a member function of std::ostream.

This necessitates that operator<< be overloaded as a friend.

Similarly, although we can overload operator+(Cents, int) as a member function (as we did above), we can’t overload operator+(int, Cents) as a member function, because int isn’t a class we can add members to.

Typically, we won’t be able to use a member overload if the left operand is either not a class (e.g. int), or it is a class that we can’t modify (e.g. std::ostream).

When to use a normal, friend, or member function overload

In most cases, the language leaves it up to you to determine whether you want to use the normal/friend or member function version of the overload. However, one of the two is usually a better choice than the other.

When dealing with binary operators that don’t modify the left operand (e.g. operator+), the normal or friend function version is typically preferred, because it works for all parameter types (even when the left operand isn’t a class object, or is a class that is not modifiable). The normal or friend function version has the added benefit of “symmetry”, as all operands become explicit parameters (instead of the left operand becoming *this and the right operand becoming an explicit parameter).

When dealing with binary operators that do modify the left operand (e.g. operator+=), the member function version is typically preferred. In these cases, the leftmost operand will always be a class type, and having the object being modified become the one pointed to by *this is natural. Because the rightmost operand becomes an explicit parameter, there’s no confusion over who is getting modified and who is getting evaluated.

Unary operators are usually overloaded as member functions as well, since the member version has no parameters.

The following rules of thumb can help you determine which form is best for a given situation:

  • If you’re overloading assignment (=), subscript ([]), function call (()), or member selection (->), do so as a member function.
  • If you’re overloading a unary operator, do so as a member function.
  • If you’re overloading a binary operator that modifies its left operand (e.g. operator+=), do so as a member function if you can.
  • If you’re overloading a binary operator that does not modify its left operand (e.g. operator+), do so as a normal function or friend function.
9.5 -- Overloading unary operators +, -, and !
Index
9.3 -- Overloading the I/O operators

29 comments to 9.4 — Overloading operators using member functions

  • Tom

    Thanks Alex, this is starting to make cents. 😉

  • madhukar

    i want to know if i can have an overloaded unary operator. (don’t know if that even makes sense.)
    i don’t see how it is possible. The problem i was thinking about was-
    suppose obj1 and obj2 are two objects of the same class.
    i want to do:
    -M1; // the operator - function returns no value, just changes the values of the data members of M1
    M2=-M1 // the operator - function returns an object of the class.
    i was thinking of using both member function and friend function together would allow me to do this, haven’t tried it yet though.
    Thanks,
    madhukar

    • madhukar

      also, when operator - is called in
      M2=-M1;
      data members of M1 remain unchanged.

      PS: im not trolling, was really wondering if its possible :S

      • Alex

        Yes, you can have an overloaded unary operator.

        If you do M2 = -M1, the unary operator- will be applied to M1 (with the result being returned by value, so that M1 isn’t modified), and then the result will be assigned to M2.

        We will look at this in more detail shortly.

  • Priyali

    Hi Alex,

    I tried overloading binary addition (+) operator using a member function as shown below.

    ------------------------------------------------------------------------------

    using namespace std;

    class Cents
    {
    private:
    int m_nCents;

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

    // Overload for Cents + Cents
    Cents operator+(const Cents &cTemp);

    int GetCents() { return m_nCents; }
    };

    // note: this function is a member function!
    Cents Cents::operator+(const Cents &cTemp)
    {
    return Cents(m_nCents + cTemp.m_nCents);
    }

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

    return 0;
    }

    ------------------------------------------------------------------------------

    The code is compiling without errors and giving me the desired output. As per my understanding, when I do c1+c2 , the call gets converted into Cents operator+(const Cents *this, const Cents &cTemp). How could “this pointer” which points to object c1 can access private member m_nCents of object c2(cTemp) even if its not a friend function. This is a bit confusing for me.

  • Joseph

    Regarding the following statement:

    “However, when dealing with operands that modify the class itself (eg. operators =, +=, -=, ++, -, etc…) the member function method is typically used because C++ programmers are used to writing member functions (such as access functions) to modify private member variables.”

    Would it be correct to say that C++ programmers mainly use friend functions to set and modify private member variables, and member functions to get and compare private member variables?

    • Alex

      No.

      Member functions are generally preferred whenever access to private members are needed. Friend functions are typically used when a function needs access to private data but a member function can’t be used (e.g. a member of one class needs access to the private data of another class). Like many things, there are exceptions. One exception is for binary operator overloads that don’t modify the left operand.

  • Vishnu

    Why Operator is not able to modify the private values when overloaded as function 1(defined below) ?

    • Alex

      Function 1 is correct. Consider your code:

      This takes object o1 and adds 10, which calls abc::operator+(int), which then returns the new object. However, your code does not do anything with this object, so it is discarded.

      You probably intended to do this:

      That way, the return value of o1 + 10 is assigned back to o1.

      Function 2 is logically incorrect. operator+ should not modify the object being called (operator += should).

  • Arun Mathew Iype

    What is the reason that the operator= should always be a member function? Can this not be done using a friend function too?

    • Alex

      C++ requires operator= to be a member function. I’m guessing that this is because C++ will auto-generate one for you if you don’t define one. If you were able to define one outside the class, the compiler wouldn’t know whether to call the auto-generated one, or the one you wrote outside the class.

  • Rahul

    "Remember that when C++ sees the function prototype Cents Cents::operator-();, the compiler internally converts this to Cents operator-(const Cents *this), which you will note is almost identical to our friend version Cents operator-(const Cents &cCents)!"

    Here, function prototype is Cents operator-();
    And if you mean to say its Cents Cents::operator-(); - which is defined outside outside the class, then the compiler would internally convert it to Cents Cents::operator-(const Cents *this) as it is a member function.

    Please clarify how compiler internally converts and links prototype and definition.

  • BlueTooth4269

    How would we overload the + operator for adding two Cents objects together as a member function?
    Is it even possible/recommended?

    • Alex

      It’s possible -- you’d do it the same way as in the Cents + int case above, but with the function taking a Cents parameter instead of an int.

      However, it’s recommended to use the friend version, as it’s both more intuitive, and more flexible (you can implement int + Cents as a friend, but not as a member, since the left operand must be a class type in the member version, and int isn’t).

  • Bro, there you have given link for section 9.6 , you missed 9.5 🙂

  • Josh W

    I’m really starting to get the Point!

    I’ve been following these tutorials for a few days now and am learning a lot more than I’ve learned anywhere else. I took a programming class in HS (it taught VB.NET) and I realize now that the teacher didn’t know anything about programming (we never talked about Object Oriented Programming for starters). Even so, I’ve been teaching myself to program in VB since then (about 8 years now) and learned quite a bit but came to a point where I decided I needed to try out C++ and find out why it’s all the rage with the kids. Every tutorial I turned to started out expecting me to already be an expert or quickly went there. This is the only tutorial I’ve found that has given me genuine instruction in C++ that has given me the confidence to tackle my own projects in this new (to me) language!

  • mrK

    hey, when i used ubuntu 14.04 to run that code, some errors make me confused "error: expected initializer before ‘operator’". ???

  • Vasant Prabhu

    Hi, I expected my code to return 12. But its giving me 5 as result.
    Not sure why this is happening.

    • Alex

      Your += operator is incorrect. += should modify the implicit object and then return that. Instead, you’re creating a new Cents object and returning that.

      So when you do c1+=7, operator c1.operator+=(7) is returning a new Cents with the value 12 that is being discarded.

      Try this instead:

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter