Functions with return values (C++)
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 ??
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:
- Why cast unused return values to void?
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.
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.
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.
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+=
.
It's simply discarded, but AFAIK C++ will show error when a function expecting return value doesn't have return statement.
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 :)
精彩评论