Do I have to return a reference to the object when overloading a pre-increment operator?

10,934

Solution 1

No, you don't have to return the reference to your object when you overload the pre-increment operator. In fact you may return anything you'd like, MyClass, int, void, whatever.

This is a design issue -- you must ask yourself what is the most useful thing to the users of your class that you are able to return.

As a general rule, class operators are the most useful when they cause the least confusion, that is, when they operate the most like operators on basic types. In this case, the pre-increment operator on a basic type:

int  i = 7;
j = ++i;

increments the variable and then returns the new value. If this is the only use you want MyClass to have, then returning a copy of your class is sufficient.

But, the pre-increment operator on a basic type actually returns an lvalue. So, this is legal:

int i = 7;
int *p = &++i;

If you want to support an operation like this, you must return a reference.

Is there a specific reason that you don't want to return a reference? Is that not a well-formed concept for your particular class? If so, consider returning void. In that case, this expression: ++myObject is legal, while this myOtherObject = ++myObject is not.

Solution 2

For question two:

Prefix returns a reference, as expected. Postfix returns a copy to be consistent with the behavior of the postfix operator(s).

Break it down simply to int:

int c = 0;

if(++c)
{
   // true, prefix increments prior to the test
}

c = 0;

if(c++)
{
   // false, c now == 1, but was incremented after the test
}

Implementing this behavior in a class requires a copy be returned because the postfix operator will have modified the state of the object.

If the program does not need true postfix operation, you are free of course to implement how you wish. While there are standard ways of writing these operators (that are understood by most C++ programmers), there's nothing actually stopping you from implementing this in different ways.

The argument provided about incorrect functionality surrounding (obj++)++ is not really important, as that code won't even compile for POD types (in Visual Studio 2010, at least), because for POD types, a copy is returned and that temporary copy cannot be used alone as an l-value.

However, for the prefix operator a reference is the preferred return as that allows the proper behavior for chaining the operation (++(++obj)).

Solution 3

Its not compulsory, but we should try to make operator overloading intuitive and it should work as per the operator which is being overloaded.

If we do int i = 10; i++ = 0 Then second statement is not allowed it says it requires lvalue as i++ denotes older state of i not a storage ... while ++i = 0 perfectly works fine .. so just to keep it in sync with actual operators prefix version had to return refence so that its return value may be treated as lvalue in expressions.

Solution 4

You can return whatever you want. void, reference to self, copy of self, something else. Whichever you prefer (or need).

If you plan using the ++ operator in chained expressions (like (++obj).something()) then return a reference. In you don't, then void is just fine.

Remember that in the end, operators are just like normal methods: you can do whatever you want with them, provided you respect their prototype.

Solution 5

Yes, you should return by reference. No need for the parenthesis around *this.

EDIT: Replying to your comment... You don't have to return by reference. But in general we follow some guidelines which make our classes behave "as expected" when compared to the builtin semantics of such operators. You might wanna take a look at http://www.parashift.com/c++-faq-lite/operator-overloading.html.

Share:
10,934
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

    Can I use:

    MyClass& MyClass::operator++ () {
        a++;  // private var of MyClass
        return (*this);
    }
    

    Or it can be:

    MyClass MyClass::operator++ ();
    

    What's the difference?


    Thanks for answers. I have another issue.

    Many people do something like that:

    MyClass& MyClass::operator++();
    MyClass MyClass::operator++(int);
    

    Isn't it illogical? Please give some examples if you can.

    I know that the first version is pre-increment and the second is post-increment, but i ask why the first one returns reference but the second one not? It is in the same code (class), and the same use of the code.

  • Admin
    Admin almost 13 years
    Ok, but can you explain why? Give some practical examples?
  • matth
    matth almost 13 years
  • Bo Persson
    Bo Persson almost 13 years
    @name3 - The best way is to do what seems logical for your class. You don't even have to increment the value, you could just as well multiply by 42 if that is the obvious thing to do for your type. For example, boost::filesystem overloads operator/ to concatenate paths instead of using it for division.
  • Dan
    Dan about 12 years
    ++i = 0 does not work perfectly fine and suffers from similar problems as i++ = 0. A variable may be set only once per sequence point. "The side effect of updating the stored value of the left operand shall occur between the previous and the next sequence point."