views:

413

answers:

6
+6  A: 

operator+ should return an instance, not a reference:

// as member function
A operator+(const A& other);

// as free function
A operator+(const A& left, const A& right);

To explain the specific problem is "returns a constant reference which is then passed to const A& operator+( int m )". Since you have a const reference, it cannot call that function because it's not a const method (i.e. const A& operator+( int m ) const).

That said, that is not the way to fix operator+. If you're returning a reference, what is it a reference to? A local in operator+ would be bad as you shouldn't return a reference to a local. A reference to a global would be bad because it will limit how your code can be used properly. A reference to allocated memory would be bad because it will leak memory. A reference to *this would be bad because then operator+ is acting like operator +=.

R Samuel Klatchko
@R Samuel: Yes, I understand. I took this out from an exam that's why I didn't change it.
jasonline
@jasonline: If you really took _this_ crap out of an exam, then, if you can, ditch that exam. That code is about as bad as you can do `operator+`, I see very little room for making it worse.
sbi
+7  A: 

which is then passed to "const A& operator+( int m )" if I'm not mistaken

No. Since the LHS is a const A& and RHS is an int, it will call*

[anyType] operator+ (int rhs) const
//                            ^^^^^ note the const here.

as you've only provided the non-const version const A& operator+( int m ), the compiler will complain.

*: Or operator+(const int& rhs) const or operator+(float rhs) const... The crucial point is that it must be a const method.

KennyTM
I like your answer, short but straight to the point.
jasonline
+1  A: 

The problem is that (a+a) returns a so-called rvalue (basically a fancy term for a temporary). While you can invoke member functions on an rvalue, you can only invoke const member functions. Also, everyone is right in saying that operator+ must alwasys return a new value.

Your operators should be implemented like this:

A operator+( const A& ) const;
A operator+( int m ) const;

However, binary operators which don't modify their left argument are probably better implemented as free functions:

class A { ... };

A operator+(const A& lhs, const A& rhs);
A operator+(const A& lhs, int rhs);

Usually, they are implemented on top of operator+=, which is implemented as a member:

class A {
  public:
   A& operator+=(const A& rhs);
   A& operator+=(int rhs);
};

inline A operator+(A lhs, const A& rhs) // note: lhs is passed by copy now
{
  lhs += rhs;
  return lhs;
}
A operator+(A lhs, int rhs) // note: lhs is passed by copy now
{
  lhs += rhs;
  return lhs;
}
sbi
@sbi: Thanks for the info, yes I know the best way should be to implement is as a global and add a constructor taking an int for the conversion. I just didn't understand the const part that's why.
jasonline
@jasonline: The best way is usually _not_ to use an implicit cast constructor, because that would require the creation of a temporary `A` from an `int`. Usually, the best way is to define distinct operator overloads for the `int` which avoid the creation of temporary. (If the constructor is trivial and all the code involved is inline, the compiler might be able to eliminate the temporary.)
sbi
@sbi: You mean define two overloaded operator where the int is on the lhs and the other where the int is on the rhs? But what's so bad about the creation of the temporary in this case anyway?
jasonline
@jasonline: Yes, that's what I mean. With your `A`, temporary or not probably won't make much difference. But think of `std::string`: If, in order to append a string literal to a string (`s1 + "blah"`) the literal had to be turned into a `std::string` first (basically, `s1 + std::string("blah")`), that might cause dynamic memory allocation and deletion and thus a serious run-time cost.
sbi
@sbi: Oh, I just thought it would be more convenient though and less redundant. But if it really causes some serious run-time cost then I guess you have a point. Thanks.
jasonline
+2  A: 

Because you are modifying the left-hand side object when adding. You can't do that with a const object. Take Samuel advice btw, because the idiomatic way is to return a new copy of the added objects.

AraK
@AraK: Yes, I understand it should return a new object. That code was taken from an exam so I didn't bother to change it.
jasonline
@jasonline: Are you sure the exam didn't implement `+=` this way? It's very hasd to imagine that any exam would get `+` that wrong.
sbi
@sbi: I guess the exam was just trying to test me if I could identify which part is causing the error. Not really trying to implement it the correct way.
jasonline
+1  A: 

The function needs to be const:

const A& operator+( int m ) const;

JonM
+1  A: 

As const A& operator+( const A& ) returns a const reference a non-const member function const A& operator+( int m ) can not be called over a const object. Either, the first operator should be defined as A& operator+( const A& ) or, the second operator as const A& operator+( int m )const; However, these changes will only make them technically correct, not aesthetically in majority of the cases, as a binary operator is not supposed to modify any of the input argument and yet to compute a result and return. Thus the result have to be returned by value or in case of C++0x , as a r-value reference. i.e A operator+(const A& rhs)const or A&& operator+(const A& rhs)const;

abir