1

I defined a Vec2 object that should represent a 2d-vector. I tried to overload the + operator to implement vectoraddition but I get following error in Line 40:

error: no match for 'operator+' (operand types are 'const Vec2' and 'const Vec2')

Here's my code:

#include <iostream>

using namespace std;

class Vec2 {
private:
    double X;
    double Y;
public:
    Vec2(double x, double y){
        X = x;
        Y = y;
    }

double getX() const {
    return X;
}

double getY() const {
    return Y;
}

Vec2 operator+(Vec2 v ){
    Vec2 res(v.getX()+X, v.getY()+Y);
    return res;
}
};

ostream& operator<<(ostream& s , const Vec2& my_vec)
{
s << " ( "<< my_vec.getX()<< " , "<< my_vec.getY() <<" ) " ;
return s ;
}

int main()
{
    Vec2 const a(3,4);      cout << a << endl;
    Vec2 const b(3,4);      cout << b << endl;

    Vec2 c(a+b);       cout << c << endl;

    return 0;
}

Interestingly when you remove the "const" keyword from a in line 37 everything works, but I don't wan't to fix the error by changing the content of the main function. I am new to operator overloading, so thanks for the help.

  • Your `operator+` should be `const` as well. (It doesn't change the contents of `this`.) – Scheff's Cat Jun 12 '23 at 15:53
  • O.T.: Actually, you could implement the `operator+` as a free-standing operator (similar like you did with `operator<<`). Free-standing functions (and operators) should be preferred over member functions when possible. – Scheff's Cat Jun 12 '23 at 15:56
  • 1
    FYI: [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/q/4421706/7478597) – Scheff's Cat Jun 12 '23 at 15:57

1 Answers1

2

The left operand, a, is const but your operator+ is not const qualified.

You simply need to make it so. Also, instead of taking the right operand, b, by value, you can (optionally) take it by const reference:

Vec2 operator+(const Vec2& v) const {
//                            ^^^^^

Demo


An alternative is to only define operator+= as a member function and then to make operator+ a free function:

class Vec2 {
public:
//...
    Vec2& operator+=(const Vec2& v) { // this changes *this, so not const qual.
        X += v.X;
        Y += v.Y;
        return *this;
    }
};

Vec2 operator+(const Vec2& lhs, const Vec2& rhs) {
    Vec2 result(lhs);
    result += rhs;     // uses the member function operator+=
    return result;
}

Demo


Alternatively:

Vec2 operator+(Vec2 lhs, const Vec2& rhs) {
    return lhs += rhs; // uses the member function operator+=
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • 1
    The link I provided above used a nice trick - giving `lhs` by value: `Vec2 operator+(Vec2 lhs, const Vec2& rhs) { return lhs += rhs; }` ;-) – Scheff's Cat Jun 12 '23 at 16:01
  • 1
    @Scheff'sCat Yeah, it's nice but doesn't play nice with NRVO so I don't think one will gain anything. It'll force a creation of a `Vec3` but it can't `NRVO` it. One optimization would be to make sure RVO is in effect and `return {lhs.X+rhs.X, lhs.Y+rhs.Y};` – Ted Lyngmo Jun 12 '23 at 16:03
  • @TedLyngmo: The advantage is that it *doesn't* force the creation of a `Vec2`. In the case of `Vec2(6, 7) + Vec2(8, 9)`, it can modify the lhs directly (since its an Rvalue) instead of making a new instance. For this `Vec2`, that's not really an advantage, but for classes with owning pointers internally, it can be a big improvement. – Mooing Duck Jun 12 '23 at 16:14
  • 1
    @MooingDuck If we take `lhs` by-value, we have forced a copy/move construction of a `Vec2` there. In this case, a copy. This `Vec2` can't be NRVO'd., but `lhs += rhs` will be RVO'd. If we instead take it by `const&` and create a named variable, we copy construct one instance and if all paths leads to `return result;` it'lll most likely be NRVO'd. Hmm, yes, perhaps it is cheaper to take it by value after all. In this case we could force RVO by `return {lhs.X+rhs.X, lhs.Y+rhs.Y};` though. :) – Ted Lyngmo Jun 12 '23 at 16:28
  • @MooingDuck I changed my answer to only create 3 instances (originally, it created 4) and added the alternative taking it by value at the bottom,. The alternative creates 4 instances and unfortunately, I wasn't able to make the alternative only create 3. – Ted Lyngmo Jun 12 '23 at 17:42