Search

9.7 — Overloading the increment and decrement operators

Overloading the increment (++) and decrement (--) operators are pretty straightforward, with one small exception. There are actually two versions of the increment and decrement operators: a prefix increment and decrement (e.g. ++x; --y;) and a postfix increment and decrement (e.g. x++; y--;).

Because the increment and decrement operators are both unary operators and they modify their operands, they’re best overloaded as member functions. We’ll tackle the prefix versions first because they’re the most straightforward.

Overloading prefix increment and decrement

Prefix increment and decrement is overloaded exactly the same as any normal unary operator. We’ll do this one by example:

Our Digit class holds a number between 0 and 9. We’ve overloaded increment and decrement so they increment/decrement the digit, wrapping around if the digit is incremented/decremented out range.

This example prints:

89098

Note that we return *this. The overloaded increment and decrement operators return the current implicit object so multiple operators can be “chained” together.

Overloading postfix increment and decrement

Normally, functions can be overloaded when they have the same name but a different number and/or different type of parameters. However, consider the case of the prefix and postfix increment and decrement operators. Both have the same name (eg. operator++), are unary, and take one parameter of the same type. So how it is possible to differentiate the two when overloading?

The answer is that C++ uses a “dummy variable” or “dummy argument” for the postfix operators. This argument is a fake integer parameter that only serves to distinguish the postfix version of increment/decrement from the prefix version. Here is the above Digit class with both prefix and postfix overloads:

This prints

5667665

There are a few interesting things going on here. First, note that we’ve distinguished the prefix from the postfix operators by providing an integer dummy parameter on the postfix version. Second, because the dummy parameter is not used in the function implementation, we have not even given it a name. This tells the compiler to treat this variable as a placeholder, which means it won’t warn us that we declared a variable but never used it.

Third, note that the prefix and postfix operators do the same job -- they both increment or decrement the object. The difference between the two is in the value they return. The overloaded prefix operators return the object after it has been incremented or decremented. Consequently, overloading these is fairly straightforward. We simply increment or decrement our member variables, and then return *this.

The postfix operators, on the other hand, need to return the state of the object before it is incremented or decremented. This leads to a bit of a conundrum -- if we increment or decrement the object, we won’t be able to return the state of the object before it was incremented or decremented. On the other hand, if we return the state of the object before we increment or decrement it, the increment or decrement will never be called.

The typical way this problem is solved is to use a temporary variable that holds the value of the object before it is incremented or decremented. Then the object itself can be incremented or decremented. And finally, the temporary variable is returned to the caller. In this way, the caller receives a copy of the object before it was incremented or decremented, but the object itself is incremented or decremented. Note that this means the return value of the overloaded operator must be a non-reference, because we can’t return a reference to a local variable that will be destroyed when the function exits. Also note that this means the postfix operators are typically less efficient than the prefix operators because of the added overhead of instantiating a temporary variable and returning by value instead of reference.

Finally, note that we’ve written the post-increment and post-decrement in such a way that it calls the pre-increment and pre-decrement to do most of the work. This cuts down on duplicate code, and makes our class easier to modify in the future.

9.8 -- Overloading the subscript operator
Index
9.6 -- Overloading the comparison operators

34 comments to 9.7 — Overloading the increment and decrement operators

  • bao

    In the overloaded postfix operator ++ and -, are you sure you can always return a copy of the temporary local variable by return by value?

    My compiler complains likes this:

    warning: reference to local variable ‘cResult’ returned

    Did you get this warning? How would you avoid it?

    • Looking at the code examples, I don’t see where cResult is returned by reference. cResult is returned by value. You can’t return local values by reference (or address) without problems.

    • Tony

      I put in a ~Digit method to notify me when one is destroyed. The overloaded postfix operators ++ and - - create a temporary digit. It appears to be destroyed when the function terminates. The calling routine gets something back, since assigning it to another Digit, and printing it, produces the expected result of the initial state.

      But this seems weird. Why is it ok to deal with an object that has been destroyed? Or am I misunderstand what's going on?

      • LW

        Here the digit is returned by value. So whoever calls the overloaded postfix operator++/- receives a copy of the object. Even if the temp variable has function scope, a copy has already made. So the code works.

        Only if the digit is returned by reference, whereas whoever calls the overloaded postfix operator++/- receives a reference to the to be deleted object (with the function scope), will cause the problem you concerned.

  • Stuart

    Why are the overloaded postfix operator++’s const but the prefix ones not?

    • Stuart

      Also, what’s the difference in putting the const keyword at the start and at the end of the statement in function declarations?

      You covered const member functions previously, where the const keyword is at the end of the statement in the function declaration; but I don’t think you’ve covered what const does at the start of the statement here.

      • Neither the prefix nor postfix operator++ is const -- however, the postfix one returns a const Digit.

        When the const is used at the end of a function, it means the entire function is const, and no member variables can be changed. When the const is used at the start of a function, it means the return type of the function is const.

  • Andrian

    The “*this” in this function refers to ‘m_nDigit’?

    • No, this always points to the instance of the class itself, so in this case this points to the Digit object that contains m_nDigit.

      That line simply invokes the prefix decrement operator on the same object that the postfix decrement operator was called on.

  • Israel

    You can replace this:

    with:

  • Aki

    i am not able to use cout << c++ <<

    i get the following error:

    complex.cpp: In function ‘int main()’:
    complex.cpp:83:11: error: no match for ‘operator<<’ in ‘std::cout << c.Complex::operator++(0)’

    • You should mark the class object parameter as "const" whenever possible, as Alex mentioned in the Overloading I/O operators lesson. In your output operator overloading function, change the second parameter to "const Complex &a" and change the prototype inside the class accordingly. That worked for me.

  • MUHAMMAD TASADDUQ ALI

    Hi , and ASSALAM O ALAIKUM

    This is my first comment .
    i am feeling happy to be part of LEARNCPP.COM.

    🙂

  • niravkarani

    ++cDigit; // calls Digit::operator++();
    cDigit++; // calls Digit::operator++(int);

    How does the compiler know when to call which function?

  • Sheik

    Hi Alex,
    Thanks for your great work and i have one small doubt. You mentioned above:

    "Also note that this means the postfix operators are typically less efficient than the prefix operators because of the added overhead of instantiating a temporary variable and returning by value instead of reference".

    I understood this, at the same time we cannot chaining this postfix operator with other operator . right ? b/c it returns by value.
    for example,  (x++) + Y; where X & Y are objects.

    It seems Alex is not reply any comments now a days. So, Others please help me in this.
    thanks in advance.

    • Alex

      You can chain operators after calling postfix, but any chained operators will be operating on the copy returned by value rather than the real object.

      You can see that here:

      If both postfixes applied to digit, the final result would be 7. But instead, the first postfix is applied to the real object, and the second postfix is applied to the copy returned by value. This means the final result is 6.

  • Do we always need to use limits while overloading increment-decrement operators? Say, I have to design a class that contains three member variables (of any type). I don’t want to limit users of the class to 10 digits and don’t want to put any limitations. I have a increment operator overloaded function for that class instances. Is it okay without limits? I am asking this because I found some kind of limitations included in every increment-decrement operator overload example I have found so far.

    • Alex

      I wouldn’t say always, but usually. The one case I can think of where it might not be needed is in the case where your class leverages dynamic memory to resize its data on an as-needed basis. Otherwise, how are you going to prevent overflow?

  • Quang

    Hi Alex, great tutorial you’re working on!
    I think there is one spot I haven’t understand, can u help me please:
        
        ++cDigit; // calls Digit::operator++();
        cDigit++; // calls Digit::operator++(int);

    I think in the functions we wrote there’s no such thing about the position of (++) and I dont know how the dummy is used so how does C++ know which one to call?

    • Devashish

      May I help you Quang?

      When you use prefix increment operator:
      C++ is smart enough to decide which overloaded operator function has to be called by looking at your statement:

      dummy is only used to distinguish between prefix and postfix overloaded operator functions. C++ can tell which one should be called by looking at your statement. I hope I am right.

      • Alex

        Yup, C++ is hardcoded to know that ++var calls the version of ++ with no parameter, and var++ calls the version of ++ with one integer parameter.

        It’s a total hack, but it works.

  • Oliver

    "Second, because the dummy parameter is not used in the function implementation, we have not even given it a name. This tells the compiler to treat this variable as a placeholder, which means it won’t warn us that we declared a variable but never used it."

    Is this an "anonymous variable" as seen in lesson 8.14?

  • Kiran C K

    I have this question. If the overloaded postfix increment operator calls the prefix operator and returns the prefix operator’s result, what is the purpose of postfix operator? Can’t we just simply use overloaded prefix?

  • Nver

    Digit Digit::operator++(int)
    {
        // Create a temporary variable with our current digit
        Digit temp(m_digit);

        // Use prefix operator to increment this digit
        ++(*this); // apply operator

        // return temporary result
        return temp;

    what is ++(*this)… I dont understand deeply this part of the code,,, pleas

    • Dave

      Nver:: The "++(*this)" increments the object temp’s m_digit.
      Alex:: The std::cout << digit++; line is executed std::cout << digit first then the temp’s m_digit is copied into digit’s m_digit?

    • Alex

      Digit is a member function, so the implicit “this” pointer points to the class object the function has been called on. *this is thus the class object itself. So we’re essentially saying “call prefix operator++ on the same object that this function was called on”.

  • Dave

    Alex, Thank you very much!
    Sorry Nver, I was dead wrong on that one.

  • Kattencrack Kledge

    In a code like this:

    Why is it printing "765" instead of "567" or "888"?

    ---

    Also, in this code:

    Why is it still printing "888" and not "678" even with the parentheses???

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter

  

  

  

nine − 6 =