Overloading unary operators: Prefix (++a) and Postfix (a++ )

Share the Article

Operator overloading helps to enable a different syntax to call functions. It helps to make programs easy to read and understand. Specifically, the only difference with functions is that in the normal function call, the parameters are enclosed in parenthesis. Whereas, with operator calls, parameters are placed in the position of their operands. The case of overloading unary operators is special as there is only one operand or parameter present.

This post explains overloading of unary ++ (or — ) operators. In C++, there are 2 ways to call them, one is Prefix (++a) increment and Postfix (a++) increment. Each type of increment shall indeed invoke a different operator overload function.

When compiler sees Prefix increment (++a), it looks for a match of type operator++( ). And when the compiler sees Postfix increment a++, it then calls operator++(int).

The following example demonstrates a simple operator overloading program.

#include <iostream> //main header using namespace std; //namespace class IntClass { int ival; public: IntClass() : ival(0) {} IntClass(int xvar) : ival(xvar) {} void printing() { cout << ival << endl; } IntClass& operator++() //pre-increment { cout << "Pre-increment" << endl; ival++; return *this; } const IntClass operator++(int) //post-increment { cout << "Post-increment" << endl; IntClass old(ival); ival++; return old; } }; int main() { IntClass ivar(4); ivar.printing(); ivar++; //Post-increment ivar.printing(); ++ivar; //Pre-increment ivar.printing(); return 0; }

Output

4 Post-increment 5 Pre-increment 6

Explanation:

The signature of overload operator is :

IntClass& operator++() //pre-increment const IntClass operator++(int) //post-increment

There are few important things to consider. Firstly, the compiler never uses the integer argument in post-increment version. This value just differentiates the 2 overloads for compiler. The compiler passes a dummy value during call.

Please note that compiler expects only an integer argument in postfix version. When the operator function uses something else, then compiler do not accept it.

The following example provides a float argument instead of int

const IntClass operator++(float) //post-increment { IntClass old(ival); ival++; return old; }

The compiler generates following error :

compiler error in overloading of postfix unary operator in c++

Postfix version returns temporary object

Secondly, the return value of postfix overloads is const. This is because, this function creates an intermittent object with previous value and then returns a temporary object with previous value. Definitely, no one should change a temporary object. Otherwise following expressions would become legal

ivar++++; //2-times post increment illegal ivar++++++; //3-times post increment illegal

This is same as

ivar.operator++(0).operator++(0); ivar.operator++(0).operator++(0).operator++(0);

Problem with temporary object

In case, the postfix version do not return a const object, like, as shown in the example. Then it will allow manipulation of returned object which is not logical. The temporary object do not exist any more and there is no point to change its value.

In following example, the temporary value is changed because the postfix do not return const object.

#include <iostream> //main header using namespace std; //namespace class IntClass { int ival; public: IntClass(int xvar) : ival(xvar) {} void printing() { cout << ival << endl; } void add_two() { ival += 2; cout << "Value=" << ival << endl; } IntClass operator++(int) //post-increment, //no const return { cout << "Post-increment" << endl; IntClass old(ival); ival++; return old; } }; int main() { IntClass ivar(4); (ivar++).add_two(); //Manipulates temporary ivar.printing(); return 0; }

The Output is:

Post-increment Value=6 5

Which one is efficient – Pre or Post ?

Finally, the return value of pre-increment contains an ampersand, hence, this is more efficient than postfix counterpart. This is because, internally no extra temporaries needed.

Implementation of pre & post version as friend functions

The following example demonstrates second way to implement pre and post version of ++ operator.

#include <iostream> //main header using namespace std;//namespace class IntClass { int ival; public: IntClass() : ival(0) {} IntClass(int xvar) : ival(xvar) {} void printing() { cout << ival << endl; } friend const IntClass& operator++(IntClass& avar); //pre-increment friend const IntClass operator++(IntClass& avar, int); //post-increment }; const IntClass& operator++(IntClass& avar) //pre-increment { cout << "Pre-increment" << endl; avar.ival++; return avar; } const IntClass operator++(IntClass& avar, int) //post-increment { cout << "Post-increment" << endl; IntClass old(avar.ival); avar.ival++; return old; } int main() { IntClass ivar(4); ivar.printing(); ivar++; ivar.printing(); ++ivar; ivar.printing(); return 0; }
4 Post-increment 5 Pre-increment 6

Main Funda: The overload of pre and post operators are two different functions.

Related Topics:

Parametrized constructor
Virtual Destructor & Pure Virtual Destructor
Smart Pointers: unique_ptr<T>
Diamond problem – Overhead of virtual base
Multiple Inheritance has multiple this pointers
Understanding multiple inheritance & virtual base classes
Understanding the copy constructor
What is move constructor ?
What is an explicit constructor ?
Smart Pointers: shared_ptr <T> 
What happens when exception thrown from a constructor?
Why a destructor should never throw exception?
Compiler Generated Destructor is always non-virtual
Which member functions are generated by compiler in class?
Understanding array version of new[] & delete[]


Share the Article

Leave a Reply

Your email address will not be published. Required fields are marked *