Operator overloading? - So Confused!

I've been watching/reading tutorial after tutorial on this topic, yet I still do not understand it.

Take the following example given in the tutorials section of this website:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// overloading operators example
#include <iostream>
using namespace std;

class CVector {
  public:
    int x,y;
    CVector () {};
    CVector (int a,int b) : x(a), y(b) {}
    CVector operator + (const CVector&);
};

CVector CVector::operator+ (const CVector& param) {
  CVector temp;
  temp.x = x + param.x;
  temp.y = y + param.y;
  return temp;
}

int main () {
  CVector foo (3,1);
  CVector bar (1,2);
  CVector result;
  result = foo + bar;
  cout << result.x << ',' << result.y << '\n';
  return 0;
}


I have a lot of confusions about this program, but rather then dump all my questions at once, lets take this step-by step.

(1) How does c++ know to call the actual operator function? I dont see a function call in main.

(2) Once the function is called, what exactly gets passed to the function as a parameter (called "param" in the above program)? Also, why does it get passed as an address value?

I have more questions, but lets get these two out of the way first.

Please keep it simple. Im a novice in programming.



Last edited on
(1) How does c++ know to call the actual operator function? I dont see a function call in main.


The call is on line 24:

foo + bar

foo and bar are both objects of type 'CVector'. Since you cannot normally add objects together like that, the compiler will check to see if there is a + overload which will allow it.

In your case, there is such an overload, so that is what is called.

(2) Once the function is called, what exactly gets passed to the function as a parameter?


For foo + bar, 'foo' is passed in as the this object, and 'bar' is passed in as the param parameter.

It works the same as if you did this: foo.plus_operator( bar );.

Also, why does it get passed as an address value?


It doesn't.

The & on line 13 denotes a reference, not an address.
Last edited on
1. C++ has something called "argument dependent lookup", where the compiler will find which function to use based on the parameters alone. This works with normal functions as well as operator functions.

2. The object to the left of the operator becomes the this pointer and the object to the right of the operator becomes the parameter. Normally you would define operator overloads as non-members, in which case you have two parameters and no this pointer.

EDIT: Ninja'd by Disch.
Last edited on
Thank you to both Disch and LB.

Got it. With that out of the way, lets move on to the big question:

(3) What exactly is happening WITHIN the operator function (lines 14-17)? Obviously a temp object is created. But what does

1
2
temp.x = x + param.x;
temp.y = y + param.y;


actually do, and how does the this pointer come into play? If things are happening behind the scenes, can you explicitly write them out for me? Thanks.

(4) How is 'temp' returned? Previously temp.x and temp.y were each assigned a certain value. I was expecting there sum to be returned. Can you explain this?
Last edited on
result = foo + bar;

'this' points to 'foo' and 'bar' gets copied to 'param';

temp.x = x + param.x;
temp.y = y + param.y;

is the same as:

temp.x = this->x + param.x;
temp.y = this->y + param.y;
Okay, I think im getting somewhere now. Here is how Im understanding this:

1
2
temp.x = x + param.x;
temp.y = y + param.y;


The above lines of code sums up the current x value (which is 3, and we know this because this is pointing to 'foo' which sent an x-argument of 3) with param.x (which is 1, and this is more-or-less obvious). This value of 4 is then assigned to temp.x

This same process is repeated for temp.y, except with the current y (pointed to by this) value and param.y (obviously).

And to answer my own question #4 from my previous post, temp is returned because it is an object of CVector, and so after its returned it is assigned to result and we can now use the dot separator with result to display 'temp.x' and 'temp.y' which we calculated earlier.

I hope im understanding this correctly. Please confirm or correct my understanding.

My last question:

(6) Why is the parameter for the operator function a const? And why is it passed as a reference? Are both const and reference necessary for operator overloading to work?
Last edited on
Both are completely unnecessary in this case.

The parameter is passed by reference probably as an 'optimization', but in this case passing by reference wont make it any faster (because CVector is too small, it is faster to just copy it).

Then, since it was passed by reference, the author added a 'const' in order to make the caller sure that the function will not be changing the argument.

Edit: it seems that you understood the rest correctly.
Last edited on
Now that we have understanding, we can start to explore.

1. What will happen in:
1
2
3
4
  const CVector foo (3,1);
  const CVector bar (1,2);
  CVector result;
  result = foo + bar;

And why?

2. Does the operator+ have to be a member function?
1. Not sure how that would change anything. You just made the objects const. The 'foo' and 'bar' objects aren't being modified anyway so what is the benefit of making them const? Not only that, 'bar' is being passed as reference and becomes a const anyway as a parameter of the operator+ function.

2. No, the operator+ does NOT need to be a member function. You can make it a friend of the class.

Thank you. Really appreciate this mini quiz. Any other questions or sample programs to help me further my understanding of operator overloading are always welcomed.
1. Not sure how that would change anything. You just made the objects const. The 'foo' and 'bar' objects aren't being modified anyway so what is the benefit of making them const? Not only that, 'bar' is being passed as reference and becomes a const anyway as a parameter of the operator+ function.

2. No, the operator+ does NOT need to be a member function. You can make it a friend of the class.

Thank you. Really appreciate this mini quiz. Any other questions or sample programs to help me further my understanding of operator overloading are always welcomed.
Also, if a non-member operator doesn't need to access private members of the class, it is recommended to have it not be a friend either.
> The 'foo' and 'bar' objects aren't being modified anyway so what is the benefit of making them const?

15. Use const proactively.

Summary

const is your friend. Immutable values are easier to understand, track, and reason about, so prefer constants over variables wherever it is sensible and make const your default choice when you define a value. It's safe, it's checked at compile time, and it's integrated with C++'s type system. ...

Discussion

Constants simplify code because you only have to look at where the constant is defined to know its value everywhere. Consider this code:

1
2
3
4
5
void Fun( vector<int>& v)
{  //...
   const size_t len = v.size();
   //... 30 more lines ...
}

When seeing len's definition above, you gain instant confidence about len's semantics throughout its scope
(assuming the code doesn't cast away const, which it should not do). It's a snapshot of v's length at a specific point. Just by looking up one line of code, you know len's semantics over its whole scope. Without the const, len might be later modified, either directly or through an alias. Best of all, the compiler will help you ensure that this truth remains true.
...

- 'C++ Coding Standards: 101 Rules, Guidelines, and Best Practices' by Sutter and Alexandrescu
also called const correctness .
1. Not sure how that would change anything.

Did you try putting that into your program and compile?


On the 2:
1
2
3
4
CVector operator+ ( CVector lhs, const CVector& rhs ) {
  lhs += rhs;
  return lhs;
}

That is not a member nor a friend. It does, however, depend on an another operator. A keyword for websearch: "canonical operator+".

Did you try putting that into your program and compile?


I got the following errors message: 24:18: error: passing 'const CVector' as 'this' argument of 'CVector CVector::operator+(const CVector&)' discards qualifiers [-fpermissive]

Can you elaborate a bit on what this means and why it happens?

Recall that you can write const after the member function parameter list. What do you think that does to the this pointer?
Just a bit of advice: if you find yourself coding a + operator, code += instead. Then operator+ is trivial:
1
2
3
4
5
6
MyClass MyClass::operator +(const MyClass &rhs) // rhs  means right hand side
{
    MyClass result(*this);
    result += rhs;
    return result;
}

Now you have two operators for the price of one.
@dhayden: you forgot to const-qualify the member function, so that code will only work sometimes.
Canonical:

1. For non-literal types, overload compound-assignment operators (like +=, -=) as member functions 
2. Overload binary operators +, - etc. as non-member non-friend functions
         a. which take the first parameter by value
         b. and delegate to the appropriate compound-assignment member function


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct cvector
{
    // ...

    cvector& operator += ( const cvector& that ) ;
    // ...
};

// note: the first parameter is *passed by value*
// note: this allows us to implement the binary arithmetic operator in terms of the compound assignment operator 
// note: this also facilitates optimisation of chained operations like a+b+c+d
cvector operator+ ( cvector a, const cvector& b ) 
{ 
    return a += b ; // delegate to compound assignment; return by value
}
I got the following errors message: 24:18: error: passing 'const CVector' as 'this' argument of 'CVector CVector::operator+(const CVector&)' discards qualifiers [-fpermissive]

Can you elaborate a bit on what this means and why it happens?

Member functions can be overloaded on constness.
See "const-, volatile-, and ref-qualified member functions"
in http://en.cppreference.com/w/cpp/language/member_functions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CVector {
  public:
  CVector operator + (const CVector&); // #1
  CVector operator + (const CVector&) const; // #2

  // other stuff
};

int main() {
  const CVector foo;
  CVector bar;
  Cvector gaz;

  gaz = foo + bar;  // calls #2, because foo is const. Cannot call #1

  gaz = bar + foo;  // calls #1, because bar is not const, could call #2 if no #1 exists

}

The const-qualifier is a promise enforced by the compiler that the const-qualified member function does not modify the object that it is called on.

A non-const-qualified member function does not promise anything and that is why in your test the compiler will not allow calling it with the const foo.
Topic archived. No new replies allowed.