In what situations would a reference be needed when overloading, as the code still works without it? I am aware it has something to with chaining, but I do not understand exactly why the reference is needed.
Example:
Object& operator++();
In what situations would a reference be needed when overloading, as the code still works without it? I am aware it has something to with chaining, but I do not understand exactly why the reference is needed.
Example:
Object& operator++();
Without the 'reference', the operator function will return by value - and that will be a copy of the original object - which is not what is intended.
For example, try the following code with and without the use of the 'reference', and you will see different results from the final one.show()
call:
#include <iostream>
class myInt {
private:
int value;
public:
myInt() : value{ 0 } { }
myInt(int x) : value{ x } { }
// myInt operator ++() { ++value; return *this; }
myInt& operator ++() { ++value; return *this; }
void show() {
std::cout << value << std::endl;
}
};
int main(int argc, char* argv[])
{
myInt one(1);
one.show();
myInt two = ++(++one);
two.show();
one.show(); // Difference shows here!
return 0;
}
This is because, without the reference, the ++
outside the parentheses operates on a locally-created copy of the one
object.
The built-in unary operator ++ returns a reference to the object for which the operator is applied.
For example you may write
int i = 10;
++++i;
So to simulate the same behavior user-defined operators also should return a reference to object.
So you can write something like: x = i++;
I don't think that it is needed; it is just used this way in general and it might cause problem in code that assumes that the operator return the value/reference - in which case you won't be able to utilize your object in that code if it doesn't return appropriate value. Furthermore, other programmers might find your code misleading if operators do weird things they don't expect.
Note: some types return copy of the object instead of reference: i++
(copy of old val) vs ++i
(new value).
Let's look at your example - we may want to increase the same object twice, therefore, we may wish to do the following:
#include <iostream>
class MyObject
{
public:
MyObject()
{
cnt = 0;
}
MyObject& operator++()
{
++cnt;
return *this;
}
int cnt;
};
int main()
{
MyObject obj{};
std::cout << "The value at start " << obj.cnt << std::endl;
++obj;
std::cout << "The value after increment " << obj.cnt << std::endl;
++(++obj); // Legal ONLY when returning a reference!
std::cout << "The value after two increments in the same time: " << obj.cnt << std::endl;
}
In this case, we increase the the counter twice using chaining, and as we expected, we get the following result:
The value at start 0
The value after increment 1
The value after two increments in the same time: 3
If we should return an object and not a reference to this, then, we operate on a l-value reference (since this object doesn't have a name!), therefore, this chaining would do nothing to the original object, as can seen in the following example:
#include <iostream>
class MyObject
{
public:
MyObject()
{
cnt = 0;
}
MyObject(const MyObject& other)
{
this->cnt = other.cnt;
}
MyObject operator++()
{
MyObject tmp(*this);
++cnt;
return tmp;
}
int cnt;
};
int main()
{
MyObject obj{};
std::cout << "The value at start " << obj.cnt << std::endl;
++obj;
std::cout << "The value after increment " << obj.cnt << std::endl;
++(++obj); // Legal ONLY when returning a reference!
std::cout << "The value after two increments in the same time: " << obj.cnt << std::endl;
}
output:
The value at start 0
The value after increment 1
The value after two increments in the same time: 2