13.8 — 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:


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


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.

13.9 -- Overloading the subscript operator
13.7 -- Overloading the comparison operators

140 comments to 13.8 — Overloading the increment and decrement operators

  • lucieon

    Hello again.
    I understand that you need the "dummy parameter" int to differentiate the signatures of prefix and postfix functions but in this code you have written in main:

    how does the compiler know ++digit must be resolved into operator++(Digit *const this) and digit++ must be resolved into operator++(Digit *const this, int)?

  • Rajendra gorana

    Prefix and postfix operator defination. I need.

  • Matt

    I do not understand how digit++ knows to call Digit::operator++(int); Neither ++digit nor digit++ attempt to pass an int to the overloaded function, so it seems to me that neither of them would have reason to call  Digit::operator++(int), in which case the return value (Digit vs. Digit&) would be the only thing that differentiates the two when pre or post increment are called... can you please elaborate on this?


    • nascardriver

      Hi Matt!

      The int parameter is only used to distinguish between the two functions, it's not actually used for anything.

      • Matt

        Hi nascardriver,
        That much I get, but I'm still not able to figure out how the post increment/decrement knows to call that function instead of the pre-version?

        • nascardriver

          I'd say it's up to the compiler to call the correct function. The standard states which operator calls which function and what's to be passed to the postfix operator as an argument.
          You'd only pass a parameter to the operator when calling it explicitly, eg. when using a pointer:

  • raj

    in the last example,what's the reason the second parameter in the output operator overload function (const Digit& d) needs to be constant.i mean, i understand the fact that since we are not making any modifications to the private member "m_digit" its better to to make the reference variable constant but if when "const" keyword is removed i get compiler error.this happens only when post incrementing/decrementing.can u please clarify the reason for this.

    • nascardriver

      Hi Raj!

      The error occurs in this line

      So let's look at @Digit::operator++(int);

      It returns a @Digit. Now, when we try to run

      The return value of digit++ is an r-value, passing it by reference would mean it's allowed to modify this object, but it isn't, because it's an r-value.
      If we tell the @operator<< to accept a const reference we don't have this problem.

  • Benjamin


    I thought of a way to create the postfix in(de)crement operators without the need of a temporary variable - at the cost of an additional arithmetic operation. Considering the Digit class as you have given it, I first overloaded operator+ and operator- :

    and then defined the postfix operators as

    As you can see, I do not need to create a temporary variable, but instead in(de)crement the Digit and return the Digit minus (plus) 1. The output of your main function

    is again "5667665". So I guess it works.

    Is there a general way to assess the performance of this approach? Is creating a temporary object more performant than the additional arithmic operation? Or it has to be considered for every case anew?

    Actually, I would like to make this question more general: there are always multiple solutions for one problem. I really want to know what is the most performant one. Besides for the fun of it, this is the main reason, why I try to learn c++. Most of my problems I used to solve in Matlab, but often my scripts need a lot of time to run. In many lessons you are already giving easy to understand and easy to remember rules about the performance of different approaches. Surely, you can't cover everything. How can I learn to figure out the performance myself without asking for each and every single case? Is there a book or tutorial about this topic? Surely there are also some tools to access the runtime of my code, right? What can I use for this purpose?

    • nascardriver

      Hi Benjamin!
      I'm happy to see you worry about performance, that's a good thing.

      Since the given functions are so similar there's an alternative to measure execution time.
      Looking at the compiled program that is.
      To do this I wrote a minimal sample program.

      I then compiled the program with g++ and loaded it in in a disassembler. The code produced by the compiler is as follows:

      You don't need to understand asm to see that the functions turned out to be equivalent.
      Result: There's no difference in performance.

      • Benjamin

        Ok, thanks for your answer. I guess I'll take a look at disassemblers then. It surely looks a bit cryptic to me, but it is good to know this as a tool.

    • Alex

      The best way to assess the performance of a given approach is to time it! You've reminded me that I had an almost complete article on how to time your code, which I've just published. Check out lesson 8.16.

      Then, whenever you have a question about whether A or B is more performant, just time them and compare.

      • Benjamin

        Great! I am anyhow repeating the classes chapter right now. So I will get there soon. Thanks!

      • Benjamin

        This also settles the answer to my original question. I measured the time it took to perform 1,000,000 increment operations:

        1) Using your implementation with a temporary variable it took 11 ms
        2) Using my implementation with temporary variable it took 18 ms

  • cybergray

    Hi Alex,

    thanks in forward for answering the following question:
    With your first program under "Overloading prefix increment
    and decrement" for testing purposes i substituted


    expecting that chaining is here possible, but got
    the output -> 111 under Visual Studio 2017.
    I do not understand this (expecting 901). Seems
    that the last Output (here 1) occurs multiple
    times (with factor chain-length). e.g. Two further
    ++digit leeds to -> 33333

    • Alex

      Using an variable with side effects applied more than once in an expression leads to undefined results. Your expression with ++digit three times violates this rule.

    • cybergray

      Thanks for answer. Please can you tell me, how can i forsee,
      if this overloaded ++- operator or other  h a v e  potential
      sideeffects, so your unique rule /* apply such variables
      only once in an expression */ fits? What happens here in the

      • Alex

        Any operator which changes the value that the variable holds applyies a side effect. So basically, ++, --, and all the operators with = in their names. There may be others as well. Note that operators like unary - are excluded, as they don't change the actual value the variable holds.

  • Akshay Chavan

    Hi Alex,

    Why does the compiler show an error when I declare std::ostream& out as a const, when overloading the operator<<

    The compiler shows the following error:

  • Curiosity

    Here, (++digit) returns an int type and digit is of type class, so how it is working perfectly even though I haven't declared (int, Digit) prototype for operator(+).
    Please Help !
    Is it due to the overloaded type-cast thing you talked about in chapter 9.1?

    • Alex

      ++digit is returning an int, which is then being implicitly converted back to a Digit via the Digit(int) constructor.

      • Curiosity

        So, It Means that when we convert an int type to a Cents Member Variable, It converts an int to Cents Class.

        • Alex

          You can't convert an int to a Cents member variable. That doesn't make any sense. You can only convert an int to an Cents object.

          • Curiosity

            How Does it implicitly convert int to a Cents Object? Can You Please Explain?
            Thanks In Advance !

            And, One More Question?
            When I used on (++digit + digit) , It printed 5Digit. Why? :)

            • Alex

              If the compiler needs a Cents object and it only has an int, it will convert the int to a Cents via the Cents(int) constructor.

              The results of are compiler specific. You'd have to ask the people who wrote the compiler why they chose that.

              • Curiosity

                But even if i make the return type of (++digit) double, It gets converted to Cents Object without the Cents(double) Constructor !
                Thanks In Advance :)

                • Alex

                  I'm not sure what you're actually doing any more. If I convert the return type of prefix operator++ to double, then (++digit) + digit doesn't compile (Visual Studio 2017), because there's no overloaded operator+ that takes a double and a Digit, nor can the double be converted to a Digit.

                • Curiosity

                  But It does work for me in CODE::BLOCKS 16.01 ! :(

    • K750i

      evaluates to

      which tries to add an Integer to a class object. Because the Digit class has a constructor that takes a single Integer parameter, the compiler will use it as an implicit conversion function and create a Digit object with 9 as an argument. Subsequently, the overloaded function

      was called to perform the addition of the two objects.

      I think most people don't realised that when a class contains a constructor with a single argument, the compiler will use it as a conversion function to perform an implicit conversion of an appropriate type. To disable this behaviour, the keyword explicit can be added to the single argument constructor as follow:

      This way, no implicit conversion occurs and only an explicit cast can be used to perform the conversion:

      I hope this clarifies the confusion and please correct me if I'm wrong.

      • Curiosity

        Thanks for the Help Bro ! But, Actually My Question Was That Why Even double + Digit Works Well ( if i change the return type of operator++(prefix) to double) even though there's no Cents(double) constructor for that and not even a operator+ that takes a double and a  Digit parameter.
        I think that the compiler implicitly casts a double to an int (through numeric conversion) which is in turn, casted to a Digit Type (through it's constructor).
        I hope you understood :)

  • C++ Learner

    Hi, can we write return m_digit instead of return *this? If the result will be different can you explain why?

    • Alex

      No, you can't. Although there is a constructor to convert an int (m_digit) to a Digit, using this constructor to return a value would create a temporary Digit, which is an r-value. However, the function returns a reference to a Digit. We can't return a reference to an r-value.

  • Omri

    It seems that the int in operator++(int), although in parenthesis and following a function name (in declaration and definition), very similar to parameter notation, should not be considered a parameter at all but rather a syntax means to tell the compiler we refer to a postfix++ call.
    You cannot replace the int with double or char etc. in this notation.
    The form resembles parameter notation very much but actually its just a convention within the language for referencing a postfix++ call, having nothing to do with any parameter.
    Am I correct?

  • Christopher

    Referring to:
    [ Digit& operator++(); // prefix
        Digit& operator--(); // prefix ]

    Are the ampersands acting as address-of operators or reference to operators, and why aren't they used in the postfix versions?

    • Alex

      The prefix operators return a reference to a Digit.

      This works for prefix ++ and prefix -- because the prefix is applied immediately, and then the resulting variable is returned. Rather than return by value, it's more performant to return by reference. However, with postfix operators, we have to return a value and THEN apply the postfix operator. That's typically done by storing the current value in a temporary variable, incrementing the real variable, and then returning the temporary by value. We can't return temporary values in a function by reference because they go out of scope when the function ends.

  • Digit& Digit::operator++()
        // If our number is already at 9, wrap around to 0
        if (m_digit == 9)
            m_digit = 0;
        // otherwise just increment to next number

        return *this;

    the above function when invoked by " std::cout << ++digit; " is supposed to return a reference to the std::cout. However, with pointer "this" as a const pointer to object digit here should return the digit object(and not a reference to the digit object) on writing *this.

    please enlighten me about the "this" and *this in this case

    • Alex

      > the above function when invoked by " std::cout << ++digit; " is supposed to return a reference to the std::cout No, this isn't an overloaded operator<< function. This operator++ returns the modified object, so that the operator can be chained in an expression (e.g. you can do this: (++digit)+=2). We return a reference to the modified object so that other operators in the expression (e.g. the +=2 in the example above) can modify the object further. If we returned by value instead, then those operators would be modifying a copy of the object rather than the actual thing. It's pretty rare that you'd ever return just "this" (no dereference).

      • thanks Alex.

        got it. i was initially confused with the fact that as "this" is a pointer to an object, dereferncing it  should yield an object (and not a reference to an object, something which is our return type in above example). Later on i got to know, for the same code, *this can yield either copy of an object(if return type mentioned is digit) or reference to the same object (if return type is mentioned as digit&).

        i couldn't express my actual doubt earlier but luckily found a helpful explanation at the following link:

        • Alex

          Just to be clear, *this always refers to the actual implicit object. Whether a copy or the actual implicit object is returned to the caller is solely based of the function's return type (by value vs. by reference).

  • methen

    class Digit
        int m_digit;
        Digit(int digit=0)
            : m_digit(digit)

        Digit& operator++(); // prefix
        Digit& operator--(); // prefix

        Digit operator++(int); // postfix
        Digit operator--(int); // postfix

        friend std::ostream& operator<< (std::ostream &out, const Digit &d);

    Digit& Digit::operator++()
        // If our number is already at 9, wrap around to 0
        if (m_digit == 9)
            m_digit = 0;
        // otherwise just increment to next number

        return *this;

    Digit& Digit::operator--()
        // If our number is already at 0, wrap around to 9
        if (m_digit == 0)
            m_digit = 9;
        // otherwise just decrement to next number

        return *this;

    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; // return saved state

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

        // Use prefix operator to decrement this digit
        --(*this); // apply operator

        // return temporary result
        return temp; // return saved state

    std::ostream& operator<< (std::ostream &out, const Digit &d)
        out << d.m_digit;
        return out;

    int main()
        Digit digit(5);

        std::cout << digit;
        std::cout << ++digit; // calls Digit::operator++();
        std::cout << digit;
        std::cout <<  // calls Digit::operator--();
        std::cout << digit--; // calls Digit::operator--(int);
        std::cout << digit;

        return 0;
    here in "std::cout << digit++; // calls Digit::operator++(int);" line , "<<" is  standard << ,not the overloaded one ,right?
    so if Digit class had 2 member variable ,would  "std::cout << digit++; // calls Digit::operator++(int);" line work.

    • Alex

      > here in "std::cout << digit++; // calls Digit::operator++(int);" line , "<<" is standard << ,not the overloaded one ,right? In, "std::cout << digit++" digit++ evaluates to a Digit, so this _is_ calling the overloaded operator<< that outputs a Digit. > so if Digit class had 2 member variable ,would "std::cout << digit++; // calls Digit::operator++(int);" line work. Yes.

  • Ehsan

    Why introduce a dummy int? Wouldn't it have been better to use the parameter to keep the temporary while also differentiating the signatures? I mean, since the object has to cloned anyway. Consider:

    What would have been wrong with this approach? It would be guaranteed that the default would always be used as there is no way to 'pass' anything else to ++.

  • Marshall H Crenshaw

    Now I understand why in for statements you always use prefix increment/decrement:

    instead of postfix increment/decrement:

    I always used the postfix because it looked more intuitive to me. i++ ‘looked’ better than ++i.
    But now I know why I should be using ++i - avoid the extra overhead of intermediate variable creation and destruction.
    Perhaps the compiler is smart enough to use the correct form.

    Never liked the trick of using the variable for something and then incrementing on the same line.

    • Alex

      Most compilers today are smart enough to optimize i++ to ++i if they can, at least for fundamental variables. However, for classes, this may not be the case.

      There's a running joke that C++ should have been named ++C.

  • 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???

    • Alex

      Using a variable with side effects applied more than once in a given expression leads to undefined results. That means you may get one result but someone on another compiler or architecture might get a different result.

      In short, don't do this. :)

  • Dave

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

  • 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".

  • 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?

  • 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?

  • 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.

  • 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?

  • 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.

  • niravkarani

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

    How does the compiler know when to call which function?



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


  • 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.

  • Israel

    You can replace this:


  • 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.

  • 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.

  • 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.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]