-2

I am trying to learn how overloading operators works in C++. I managed to figure out how to implement the += and = operators, but I am struggling with the + operator. The compiler tells me that the operator can only take one or two arguments. I can't seem to figure out how to properly return the result.

The objects I can take as arguments would be the LHS and RHS of the operator, but it seems to me that I have to create a third instance of the class somehow to store and return the result. I don't think the + operator is supposed to be modifying either the LHS or the RHS themselves.

Furthermore, creating a new instance within the method would not work, since that object would be removed after the method finishes.

So how do I properly store the result in a fresh instance?

This is what I tried so far:

#include <iostream>

class smallclass
{
public:
    smallclass();
    smallclass(int x);

    smallclass& operator+=(smallclass&y);
    smallclass& operator=(smallclass& y);
    smallclass& operator+(smallclass& y);
    int a;

};

smallclass::smallclass()
{

}

smallclass::smallclass(int x)
{
    this->a = x;
}


smallclass& smallclass::operator+=(smallclass&y)
{
    this->a += y.a;

    return *this;
}

smallclass& smallclass::operator=(smallclass& y)
{
    int value = y.a;
    this->a = value;
    return *this;
}


smallclass& smallclass::operator+(smallclass& y)
{
    int value = y.a;
    this->a += value;

    return *this;
}


int main()
{
    smallclass a = smallclass(5);
    smallclass b = smallclass(6);

    std::cout << a.a << std::endl;
    std::cout << b.a << std::endl;
    // a = 5
    // b = 6

    a += b;

    std::cout << a.a << std::endl;
    std::cout << b.a << std::endl;
    // a = 11
    // b = 6

    a = b;

    std::cout << a.a << std::endl;
    std::cout << b.a << std::endl;
    // a = 6
    // b = 6

    smallclass c;

    c = a + b;

    std::cout << a.a << std::endl;
    std::cout << b.a << std::endl;
    std::cout << c.a << std::endl;
    // a = 12 should be 6
    // b = 6
    // c = 12

    return 0;

}
JAD
  • 2,035
  • 4
  • 21
  • 35
  • 2
    You should probably flag `operator+` as `const` so you don't accidentally modify anything. Make a copy of your object, add to it, return that. – tadman Dec 13 '17 at 21:29
  • Your `operator=` fails to return a value, thus the behavior is undefined. – PaulMcKenzie Dec 13 '17 at 21:30
  • @PaulMcKenzie woops, fixed I hope. – JAD Dec 13 '17 at 21:32
  • You don't need to implement the assignment operator, the compiler does it for you. Also, https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading – juanchopanza Dec 13 '17 at 21:33
  • 2
    `operator +` should be returning a brand new instance of `smallclass`, not the original instance or a reference. `return smallclass(*this) += y;` – PaulMcKenzie Dec 13 '17 at 21:33
  • `operator +` is easy if you already have `operator +=` and a copy constructor. (Though you will want to return by value rather than by reference.) – cHao Dec 13 '17 at 21:33
  • BTW, you don't need the `this->` syntax to access class methods or members. The exception is to differentiate member names from parameter variable names (which can be resolved by using different names). – Thomas Matthews Dec 13 '17 at 21:44

2 Answers2

4

You are returning *this from operator+. You should instead return an object that contains the new result. By returning *this you are saying that the result of x + y is always x, which is not true. The result is a new value, distinct from both x and y. Notice that the return type should not be a reference, since the returned value doesn't refer to any existing instance.

smallclass smallclass::operator+(smallclass& y)
{
    smallclass result;
    result.a = this->a + y.a;
    return result;
}

You should also read about const correctness. By making y a const reference you guarantee the user that your operator will not modify y. The same is true about making the entire member function const. It guarantees to the user of your class that the operator won't modify this. Without these const you will not be able to use your operator with const instances.

smallclass smallclass::operator+(const smallclass& y) const
{
    smallclass result;
    result.a = this->a + y.a;
    return result;
}

A more idiomatic approach is to implement operator+ in terms of operator+= and of the copy constructor. That way, you don't have to repeat yourself.

smallclass smallclass::operator+(const smallclass& y) const
{
    smallclass result(*this);
    result += y;
    return result;
}

You can do this for many operators. Notably the comparison operators can be all be implemented in terms of only two fundamental comparisons, for example operator== and operator<.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
3

The canonical version of implementing operator+ is this:

friend smallclass operator+ (smallclass op1, smallclass const& op2) {
   op1 += op2;
   return op1;
}

This approach leverages copy-elision where possible and also leveraged the existing implementation of operator+=.

If you want to inhibit auto conversion on the left hand side you can use the version below for a commutative addition:

smallclass operator+ (smallclass rhs) const {
    rhs += *this;
    return rhs;
}

If the addition is not commutative you’d use

smallclass operator+ (smallclass const& rhs) const {
    return smallclass(*this) += rhs;
}

(the last version can’t entirely elide one copy).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • I would note this is canonical assuming you want auto conversion of the lhs from `int` to `smallclass`. If not then a member method is more appropriate. – Martin York Dec 13 '17 at 21:57
  • @LokiAstari: since you get auto conversion on the rhs and addition is commutative it seems consistent to have auto conversion on the lhs, too. – Dietmar Kühl Dec 13 '17 at 21:59
  • It "leverages copy elision where possible" except for NRVO. So if the LHS is an lvalue it could be less optimal than the version taking lvalue references and making a copy in the body of the function. – juanchopanza Dec 13 '17 at 22:28
  • @DietmarKühl Don't disagree with that point. Just thought it was worth pointing out as the OP question does not have enough context. – Martin York Dec 13 '17 at 22:29