3

When main() calls a function which has a return value of some datatype ( primitive or user-defined ) , the statement in which the function is called is 'usually' an assignment .

Ex :-

class complex
{

private:

    int real;
    int imag;

public:

    complex();
    complex(int r,int i);
    complex operator + (complex c);
};

Suppose , the definition of my overloaded " + " is like this -

complex complex::operator + (complex c)
{
    this->real = this->real + c.real;
    this->imag = this->imag + c.imag;
    return *this;
}

I have my main function as follows -

int main()
{
    complex c1;
    complex c2(5,4);
    c1+c2;
}

In the main() above , consider the statement c1+c2 . The compiler treats it as c1.operator + (c2) . When this function is called by main , it returns a value to main() . What happens to this return value ??

progammer
  • 1,951
  • 11
  • 28
  • 50
  • Don't overload `operator +` like that. Can you imagine if saying `y = x + 7` modified the value of `x`? – Travis Gockel Sep 11 '11 at 05:53
  • @Travis .. Thanks for the suggestion :) .. I understand it . But i m a beginner in C++ and trying to explore things in various ways . – progammer Sep 11 '11 at 05:56
  • nitpick. Don't overload the + operator by passing in the rhs by value. Pass it in by reference. That, is declare the function as "complex& complex::operator + (complex& c)". – selbie Sep 11 '11 at 06:21
  • 1
    Your `operator+` looks like it should be `operator+=`. That's even what you're doing to the `real` and `imag` members: compound assignment. – Luc Danton Sep 11 '11 at 06:24
  • @Luc Danton: Exactly. I've explained that in my detail answer. – Nawaz Sep 11 '11 at 07:11
  • What do you mean "what happens to it"? Why should anything necessarily happen to it? – Karl Knechtel Sep 11 '11 at 08:36

6 Answers6

8

The value of the expression c1+c2 is ignored by your code, as you are not storing it anywhere. At most, the compiler will print some warning messages. To supress such warning messages, you could write :

(void)(c1+c2); //casting to void suppresses the warning messages!

See this:


The real issue with your code..

However, in your code, the implementation of operator+ is not semantically correct. To understand that consider this,

 int a=10;
 int b=5;

then, do you expect a+b to change the value of a? Should a become 15? No.

If you want that, then you would write a+=b instead. But in your code, c1+c2 behaves equivalent to the semantic of c1+=c2, as you're updating the value of this->real and this->imag in your implementation of operator+, which is not correct, semantically.

So the first fix is this:

complex complex::operator + (const complex& c) const
{                            
  complex result(c); //make a copy of c
  result.real += this->real; //add
  result.imag += this->imag; //add
  return result;
}

Now, this is semantically correct.

That said, there is still few things to be noted. When you write c1+c2, do you think the operation + is applied on either of the object? No. It doesn't apply on any of them, yet the member function operator+ gets invoked on c1 object which becomes this pointer inside the function. Why should it be invoked on c1 (or for that matter c2) if the operation doesn't apply on it?

This analysis makes it clear that operator+ shouldn't be a member function of the class. It should be a non-member function instead, and the signature then would be:

complex operator+(const complex &a, const complex &b);

But there is a small problem: in the computation of a+b, it needs to access to the private members of the class (real and imag are private members). So the solution is, operator+ should be implemented in terms of operator+=, and the latter should be added as a member function to the class, because the operation += in the expression a+=b does apply on a, as it modifies its value.

So here is my implementation of both operators:

class complex
{
  //...
  public:

    //member function
    complex& operator+=(const complex & c)
    {
          real += c.real; //same as: this->real+=c.real; this is implicit
          imag += c.imag; //same as: this->imag+=c.real; this is implicit
          return *this;
    }
};

//non-member function (its non-friend as well)
complex operator+(const complex &a, const complex &b)
{
    complex result(a); //make copy of a by invoking the copy-constructor
    result += b;  //invokes operator+
    return result;
}

Or you could join last two statements as:

complex operator+(const complex &a, const complex &b)
{
    complex result(a); //make copy of a by invoking the copy-constructor
    return result += b;  //invokes operator+, and then return updated 'result'
}

But there is another way to make copy. Why pass both arguments by reference? Passing the first argument by value would make the copy we need. So a better implementation would be this:

complex operator+(complex a, const complex &b)
{               //^^^^^^^^^ pass-by-value
    a += b; //a is a copy, after all - we can modify it!
    return a;
}

Hope that helps.

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Thanks a loot :) . I knew that it was inappropriate to use the operator+ with that definition I gave . But I was not stressing on that fact . Its my mistake to have written that function 'loosely' , but what actually I want to know about is the discussion K-ballo and I were having. Please can you leave your comments on that ? – progammer Sep 11 '11 at 09:11
  • Good answer but I'm not sure I'm convinced by your argument about operator+() belonging outside the class. If we follow your reasoning, every const member function of a class should be made into a non-member function accepting a const reference to an object since it doesn't "apply" to it. I think it makes sense for it to be a member, since it's conceptually tied to the class. – neuviemeporte Aug 23 '12 at 16:28
  • @neuviemeporte: There is another point which you missed. The const member function may need to access the private and protected members, then you cannot make it non-member function; you have to make it member function. The idea of non-member function comes when a functionality can be implemented in terms of public functions of the class, that you increase encapsulation, as the private and protected members are hidden from the non-member function, yet you're able to provide some functionality to the users. – Nawaz Aug 23 '12 at 16:32
  • 1
    Thanks for clarifying. I mostly agree, but I still believe that if we were to follow that to the letter, we risk needlessly polluting the namespace outside the class with too many free-floating non-member functions. If they work with the class, they belong in the class, I reckon. Perhaps not in this one, but global functions smell. – neuviemeporte Aug 23 '12 at 16:50
  • 1
    @neuviemeporte: In that case, I'll suggest you to read this article by Herb Sutter : http://www.gotw.ca/gotw/084.htm . It is a very well written article. – Nawaz Aug 23 '12 at 16:55
2

It gets assigned into a temporal (invisible if you may) complex value. The lifetime of such value is until the expression that generated it ends, that's the ; at the end of c1+c2. So a new temporal object is created to store the result of the expression, and its destructed at the end of that line.

You shouldn't be modifying 'this' in your a + b operator, after evaluating a + b now a holds the result of the expression.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • But the expression which generates that _temporal object_ is **return *this** .. Is nt it so ? – progammer Sep 11 '11 at 05:58
  • No, return *this generates another temporal that then gets copied into the temporal that's returned from the function (compilers are allowed to elide that copy, and they usually do). That temporal object is generated by copy constructing the return value of the function. – K-ballo Sep 11 '11 at 06:00
  • I dont know whether this is right or wrong . But this is what I understood - _"The statement **c1.operator+(c2);** , speaking 'loosely' has a temporary object (let say t1) and the statement **return *this;** when executed creates one (let say t2).By the time the **;** of return statement is reached **t2 is destroyed** and it's value is already stored in **t1** . Now, in this particular scenario , **t1** is destroyed as soon as the execution reaches **;** of the statement **c1.operator+(c2);** "_ – progammer Sep 11 '11 at 06:06
2

The return value is discarded; as you are not storing it anywhere.

One important advice:

Ideally the definition for operator + should look like.

complex complex::operator + (const complex& c)
{                            ^^^^^^^^^^^^^^
  complex add; 
  add.real = this->real + c.real;
  add.imag = this->imag + c.imag;
  return add;
}

In your original code 2 copies of complex are made; among which at least 1 can be avoided with above format where the argument is pass by const reference.

Also, in your code you should not change the current object; (otherwise it becomes like operator +=()). So create a temporary inside the function and pass it by value.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 2
    +1 for the advice. But the advice is not entirely and semantically correct. `operator+` shouldn't change the object on which its called . That is, `a+b` should NOT change `a`, instead `operator+` should create a local variable, and that should be returned. So the signature would be `complex complex::operator + (const complex& c) const`. Make the function const. – Nawaz Sep 11 '11 at 06:05
  • I meant, *That is, `a+b` should NOT change `a`*. I edited my previous comment. – Nawaz Sep 11 '11 at 06:10
  • @Nawaz, correct. Actually, since the result of `a+b` was not used in the real code; I thought of optimizing the `return` value also. ;) However, that cannot be a general good advice, so edited it. – iammilind Sep 11 '11 at 06:17
  • You didn't mention in your answer that `a+b` shouldn't change `a`. Instead, `operator+` should create a local variable and that should be returned. – Nawaz Sep 11 '11 at 06:19
  • Since there are many things to be said, so I better posted an answer, as yours doesn't cover them all. – Nawaz Sep 11 '11 at 06:48
1

In this case, it is silently dropped (but the sum is stored in c1 or c2). The compiler might (or might not) optimise the code by dropping the line entirely, because it doesn't do anything substantial. The resulting sum will be constructed and returned by the operator+, (a temporary variable will be created) and then destroyed immediately.

This happens in other cases, too. Consider this:

c2 += c1;

You can chain several additions like this together:

c4 += c3 += c2 += c1;

This is because operator+= also returns a value, but it is ignored like in your code.

By the way, I think you want to use operator+=.

evgeny
  • 2,564
  • 17
  • 27
0

It's simply discarded, but AFAIK C++ will show error when a function expecting return value doesn't have return statement.

LeleDumbo
  • 9,192
  • 4
  • 24
  • 38
0

Another solution is to use operator + in global scope but as a friend of your class:

class complex
{
    // ...

public:

    // ...

    friend complex operator +(const complex &c1, const complex &c2)
    {
        complex c;
        c.real = c1.real + c2.real;
        c.imag = c1.imag + c2.imag;
        return c;
    }

    // ...

};

Using this technique you can also use an integer as argument (at the lhs) by adding:

    friend complex operator +(const int n, const complex &c)
    {
        complex c;
        c.real = n + c.real;
        c.imag = c.imag;
        return c;
    }

    friend complex operator +(const complex &c, const int n)
    {
        complex c;
        c.real = c.real + n;
        c.imag = c.imag;
        return c;
    }

So now you can also do

 complex c1, c2, c3;
 c3 = 1 + c2 + 8 + c1 + 2;

and your class is missing a (virtual) destructor, I would also make the member variables protected instead of private :)

demorge
  • 1,097
  • 1
  • 7
  • 17