1

This is a code for adding 3 objects of class Integer

#include <iostream>
using namespace std;
class Integer
{
    int value;
    public:
    Integer(int i) 
    { 
        value = i; 
    };
    int getValue() 
    { 
        return value; 
    }
    friend Integer operator+(const Integer & a,const Integer & b)
    {
        Integer i(a.value+b.value);
        return i;
    }
};
int main()
{
    Integer a(1), b(2), c(3);
    Integer d = a + b + c; //****HERE****
    cout << d.getValue() << endl;
    return 0;
}

Can someone please explain why const is added to parameters in this case. If I remove const, during compilation I get invalid operands to binary operation error. Adding to this question: When I only add a and b without const, output is 3 without any errors. However, adding 3 a+b+c objects, I get an error. Why is that?

  • If you don't use `const` then it allows for the possibility of a binary operator to modify an operand, which is not allowed. – Eli Sadoff Nov 04 '16 at 14:21
  • As a style note, you're also not changing a or b; nor would you ever want to in that operator - so using const will also protect you from doing silly things by mistake in that function... – UKMonkey Nov 04 '16 at 14:25
  • @EliSadoff A binary operator is *allowed* to modify an operand. Whether it *should* do it is a separate question. – Barry Nov 04 '16 at 14:32
  • @EliSadoff: This analysis is incorrect. See the answers from Xirema and Barry, that I've just upvoted. – Bathsheba Nov 04 '16 at 14:33
  • @Bathsheba I realized as such. I apparently misunderstood the concept myself. – Eli Sadoff Nov 04 '16 at 14:34
  • As a service to future readers and people searching for a problem on Google, it is always a good idea to copy & paste the exact error into the question. – Christian Hackl Nov 04 '16 at 15:22

2 Answers2

2

Let's say hypothetically we had written this function:

friend Integer operator+(Integer& a, Integer& b);

Stylistically, this isn't great because operator+ shouldn't be modifying its arguments. But let's say we don't care about that. Now, what happens when we try to do this:

Integer d = a + b + c;

This is grouped as (a+b)+c. The a+b subexpression will find our operator+(), which is a viable function because a and b are non-const lvalues of type Integer, and the result of that expression is an rvalue of type Integer.

The subsequent expression is {some rvalue Integer} + c. That expression we won't be able to find a viable function for. While c can bind to Integer&, the first argument cannot - you can't bind an rvalue to a non-const lvalue reference. So you'd have to write something like:

Integer tmp = a + b; // OK
Integer d = tmp + c; // also OK

but now we're introducing this extra name into our scope and an extra statement into our code just to get around the unviability of our function signature.

Barry
  • 247,587
  • 26
  • 487
  • 819
2

Because you're trying to bind a Temporary to a [non-const-]reference, which isn't allowed in C++.

In the code Integer d = a + b + c;, a + b is evaluated first, and creates a new temporary object which then gets evaluated against c. So the code then becomes Integer d = t<a+b> + c;. Because the first object is now a temporary, only three function signatures will accept it as a parameter: const Integer &, Integer, and Integer &&. The second is not advised because it will create a copy of the object (though, sometimes that's what you want!), and the latter isn't advised because it will refuse to accept persistent objects. The first option, then, is best, because it will accept any Integer object regardless of whether it's expiring or not.

Recommended Reading: What are rvalues, lvalues, xvalues, glvalues, and prvalues? It's very verbose, and will probably require several passes before you "get" it, but it's extremely valuable knowledge for any C++ programmer.

Community
  • 1
  • 1
Xirema
  • 18,577
  • 4
  • 26
  • 60