1

I have the following code inside Movie class:

Movie& operator+ (const Movie& other);

Now I want to overload this a few times, say MOVIE1 + MOVIE2 + MOVIE3 + MOVIE4

When I try to do:

Movie& operator+ (const Movie& left, const Movie& right);

It gives me error :

must take zero or one argument

While searching I saw a few solutions, none of which worked for me.

7
  • 1
    Is the second version declared inside Movie? It should be a non-member function. Commented Nov 24, 2015 at 11:46
  • 1
    And it seems very strange to return a reference from operator+. Are you sure you don't want to return by value? Commented Nov 24, 2015 at 11:48
  • Im not sure what is the difference.. refernce would work out wouldn't it? Commented Nov 24, 2015 at 11:50
  • 1
    Actually you don't need overloaded operator+()... first definition handles the condition you are talking about... think why Movie& is returned... Commented Nov 24, 2015 at 11:50
  • 1
    a simple operator+(const Movie& other) is all you need to be able to write movie1+movie2+movie2... Commented Nov 24, 2015 at 11:53

6 Answers 6

3

You don't need anything special to chain additions, you just need a correct operator overload.

The best way to implement operator+ is to implement operator+= for your class, then write operator+ as a non-member function in terms of operator+=. This gets you two operators for the price of one, lowers code duplication and treats left and right arguments symmetrically with respects to implicit conversions.

An issue with your implementation is that you return a reference to a Movie. This would require either dynamically allocating the Movie and remembering to delete it (inefficient, error prone), returning a reference to a local (undefined behaviour) or having some more complex system in place (unnecessary). You should just return by value.

Here's what an implementation could look like:

class Movie {
public:
    Movie& operator+= (const Movie& rhs) { 
        m_data += rhs.m_data;
        return *this;
    }

private:
    int m_data; //assume some data
};

Movie operator+ (Movie lhs, const Movie& rhs) {
    lhs += rhs;
    return lhs;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Nice answer. I wrote twice as much without saying as much and threw it away.
0

You do not have to overload the operator to add many objects, this is already handled by the operator+ you have. You should only change it to return a value not a reference :

struct A {
    int value;
    A() : value(1) {}
    A operator+(const A& other){
        A result;
        result.value = this->value + other.value;
        return result;
    }
}; 

int main() {
    A a,b,c;
    A d = a + b + c;
    std::cout << d.value << std::endl;
    return 0;
}

3 Comments

this one i guess compiles.. but does it return the right answer?
@aviadm71 yes it does. Why do you think it should not?
@aviadm71 just think of all the pod types, they do not need to provide all kinds of overloads, but you can write int a = 1 + 2 + 3 + 4 + 5 for an arbitrary number of operands
0

You don't require overloaded definition of operator+().

Movie MOVIE5 = MOVIE1+MOVIE2+MOVIE3+MOVIE4;

To understand you can expand this as

Movie MOVIE5 = MOVIE1+MOVIE2+MOVIE3.opertor+(MOVIE4);

operator+MOVIE3.opertor+(MOVIE4) returns Movie object, which is then added with MOVIE2 object and their result will in turn added to with MOVIE1 finally returning result in MOVIE5 object

Comments

0

The first definition:

Movie& operator+ (const Movie& other);

already allows you to chain the operator + in a statement like the one you want to write :

MOVIE1+MOVIE2+MOVIE3+MOVIE4; // assumes all those variable are of type Movie

The reason it works is that the operator returns a non-const reference to Movie (Movie& in the function declaration). This return value becomes the left operand of the next operator +.

MOVIE1+MOVIE2+MOVIE3; statement is equivalent to (MOVIE1+MOVIE2)+MOVIE3;. We can see it is composed of two expression (whose operator is + for both). The first expression evaluated is MOVIE1+MOVIE2. The return value becomes the left operand for the second addition, with MOVIE3 as the right operand.

EDIT: As pointed out by TartanLlama, you probably want to change the signature of your first method to:

Movie operator+ (const Movie& other); // return a value instead of a reference

Because you could be returning a reference to a local object, which will lead to undefined behaviour.

2 Comments

What will the operator return a reference to?
@TartanLlama Thanks for catching that, let's assume there is not a clever cache mechanism behind this operator + (but then, what does it mean to sum up movies ;)
0

Operators can be chained normally: if you have operator + defined for adding two Widgets and returning a Widget, you can add as many Widgets with it as you like. The reason is simple:

a + b + c + d

is parsed as

((a + b) + c) + d

However, there's something wrong with your operator declaration: you're returning a reference to a Movie. That makes no sense for an operator like +, which creates a new value rather than modify an existing one. You should be creating a separate Movie object inside the operator, and returning it by value.

Generally, the best way of handling operators like this is to implement the operation&assignment variant in class, and building the binary operator as a non-member function on top of that. Something like this:

class Movie
{
  // ...
  Movie& operator+= (const Movie &rhs)
  {
    //somehow add rhs to this
    return *this;
  }
  // ...
};

inline Movie operator+ (const Movie &lhs, const Movie &rhs)
{
  Movie result = lhs;
  result += rhs;
  return result;
}

There's one more point: though. What does it mean to add two movies together in the first place? Overloading operators for the sake of shorter syntax for some arbitrary, unituitive operation leads to unreadable and hence unmaintainable and hence bad code.

Unless you're building a DSL (which you're probably not), I'd stick with named functions for the sake of maintainability.

Comments

-2

The + operator is a so called binary operator (as opposed to unary). That means it takes exactly two arguments: "left hand side" <operator> "right hand side"

Only non-member binary operators take two arguments.

As the left hand side in member-methods is always the current object this, all member binary operators take only one argument.

That is the reason you won't find a solution for this.

What you can do instead is to return an array of movies.

3 Comments

Non-member binary operators take two arguments.
how would returning an array of movies help?
I guess what the OP tries to accomplish is to have a list of movies. So that is an array (or std::list or QList or what ever lib you are using).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.