C++ Operator Oveloading









C++ Operator Overloading and User Defined Class Objects


Operator overloading means ‘providing different functionality to an operator under a different environment. Majority of the C++ built-in operators are already overloaded. Like functions, operators take operands (arguments) and return a value. As such operators can also be overloaded to act in a specific manner on the argument or arguments and return a value. For example, the plus (+) operator is overloaded to add two integers, increment an integer by one and concatenate a string. Likewise a minus (-) operator is overloaded to subtract two integers, and decrement an integer by one. Like the + and –, C++ provides in-built overloaded definitions for most operators to perform various functionalities directly but only on built-in types. However, C++ provides abilities for a programmer to overload built-in operators to act on user-defined types in a user-defined manner.

However, operator overloading does not imply a functionality of the operator different from its in-built designation. The following rules constrain how overloaded operators are implemented. However, they do not apply to the new and delete operators, which are covered separately.

C++ enables overloading of most operators to be sensitive to the context in which they applied. Overloaded operator function performance can also be achieved by other ordinary functions but operator notation provides clarity and more familiar functionality to programmers and users. Operator overloading makes a program clearer than use function calls to accomplishing the same functionality. C++ allows for most existing operators to be overloaded so that, when used on user-defined objects, they have meaning appropriate to those objects.

An operator is overloaded by writing a function whose is keyword operator followed by the symbol for the operator being overloaded. For example, to overload the + operator we write the keyword operator followed by the plus (+)( as in (as in operator+), All other operators are overloaded in the same way. Apart from the difference on the function name, operator overloading functions are written like any other function. However an operator overloading function must be a non-static member function be called on an object of the class and operate on that object.

As indicated C++ has a built-in mechanism on how to work with the plus operator (+) when it is applied to integer operands. For example if we write our function as follows;

int addNos(int x, y)
{ int z=x+y;
return z;}
and then we make a function calls as;
					addNos(5,4);

The compiler knows that we are adding X to Y (i.e. 5+4) and function addNos will return the result 9. But in a situation where we have our own defined type, the compiler will not know exactly what we want. In other words, the above function does not necessarily work in the same way as the one below ;

children addNos(int g, b)
{ int t=g+b;
return t;}

Type ‘children’ is user defined and the compiler does not know how to work with it and so the call;

					addNos(5,4);

does not result in 5+4 unless we have specifically defined the operator + to work on user defined ‘children in the same way, it does with a built-in type like int.

An operator must be overloaded before it is applied on a class object. However there are three exceptions to this rule. The assignment operator (=) by default can be used with every class to perform memberwise assignment of the data members of the class. However default memberwise assignment is dangerous for classes with pointer members and so for such classes, it is important to explicitly overload the assignment operator. The address (&) which returns the address of the object in memory and comma (,) operators may also be used with objects of any class without overloading.

Operator Overloading Guidelines

The majority of C++'s operators can be overloaded. Save for operators ?: :: . and >* which cannot be overloaded, all the others shown in the table below can be overloaded

Operators that can be overloaded
+ - * / % ^ &|
~ ! = > < += -=*=
/= %= ^= &= |= < < > > >>=
<<= == != <= >= && ||++
-- ->* , -> [] () newdelete
new[] delete[]


Operator overloading must maintain the following rules

  • Operator overloading does not change the functional use of the operator . The + operator must perform addition, the – must subtract, the * must multiplication and all other overloaded operators must perform their built-in functionality.



  • Overloading does not mean change of the precedence of an operator. If you are not sure of the precedence use the parentheses to force the order of evaluation of overloaded operators in an expression.



  • The associativity of an operator i.e the order in which the operator evaluates its operands cannot be changed. If the operator evaluates from right-to-left or left-to-right, this cannot be changed by overloading.



  • The number of operands an operator takes (i.e. the arity of the operator) cannot be changed by overloading Operators using single arguments (i.e unary operators) remain cannot be made to take on more than one arguments; Likewise overloaded binary operators must maintain use of two arguments.



  • No new operators can be created by overloading. This is at times disadvantageous because its limits the programmer from using common notations like the ** operator for exponentiation. However, the ^ operator to can still be overloaded to achieve the same level of exponentiation



  • Each operator must explicitly be overloaded. Overloading an operator does not implicitly overloaded its closely related operator. For example overloading the + operator does not overload its related operator += and overloading == operator does not overload != operator.

Placement of Operator Functions

Operator functions can be member functions or global functions and then made friends for performance reasons. However some operators must be overloaded as member functions. These include (), [], -> or any of the assignment operators. For the other operators, their overloaded operator functions can be either class members or global functions.

To implement as a member overloaded function, the leftmost operand must be an object or a reference to an object of the operator's class. Operator member functions are called implicitly only when the left operand of a binary operator is specifically an object of that class, or when the single operand of a unary operator is an object of that class. Thus if the left operand has to be an object of a class or any other user-defined type, the operator must be overloaded as a global function and where necessary made a friend of the class to enable the function access private or protected members of that class directly.

Overloading Arithmetic Operators

Where arithmetic operators are implemented as binary operators, they can be overloaded as a non-static member function with one argument or as a global function with two arguments. Below is an example that overloads the +,-,* and / operators as member functions.

#include<iostream>
Using namespace std;

class Share
{
friend ostream& operator<<(ostream&, const Share&);

public:
Share (){}
Share (double convInt)
{
Qty=convInt;
}

Share operator+(const Share &right)
{
return Share(Qty+right.Qty);
}

Share operator*(const Share &right)
{
return Share(Qty*right.Qty);
}


Share operator/(const Share &right)
{
return Share(Qty/right.Qty);
}

Share operator-(const Share &right)
{
return Share(Qty-right.Qty);
}

private:
double Qty;

};

ostream& operator<<(ostream& print, const Share &s)
{
print<<s.Qty;
return print;
}


int main()
{
Share OrangeUnits=5, QtyPerUnit=20;

Share totalOranges=OrangeUnits*QtyPerUnit;

Share FormAStudents(20), FormBStudents(30);

Share totalStudents=FormAStudents + FormBStudents;

Share OragesPerStudent=totalOranges/totalStudents;

Share NosExtraInB=FormBStudents-FormAStudents; 

cout<<"There are "<< totalOranges<<" oranges to be share by "<<totalStudents <<" students \n"
<<"Each student will consume "<<OragesPerStudent<<" Oranges.\n" 
<<"Students in form B will consume "<<NosExtraInB*OragesPerStudent<<" more oranges than those in form A.";

return 0;
}

Output:

There are 100 oranges to be share by 50 students 
Each student will consume 2 Oranges.
Students in form B will consume 20 more oranges than those in form A.

Once we have overloaded an operator and a function call is made, the appropriate overloaded version of the operator is called based on parameter type used. For example in in our example above, each versions of type double of overloaded operators for +,-,* and / is called respectively whenever we add, subtract, multiply or divide any two objects of our class ‘Share’. The constructor in the example uses the type conversion technique. We used this technique to be able to convert from type double to type Share. For details on this technique refer to type conversion section below.

Member functions use the this pointer implicitly to obtain one of their class object arguments (the left operand for binary operators) . Arguments for both operands of a binary operator must be explicitly listed in a global function call. Other overloaded operator functions may also be made global functions if there is need to enable the operator to be commutative. For example in the day-to-day arithmetic, the order of operands to +, or - or * operators does not matter. But in C++ it requires that the overloaded function be made a member of the class if the left most operand is an object of the class. In other words where “A” is an objects of the class and B is not, then A+B or A-B or A*B will not work the same as B+A or B-A or B*A respectively. To avoid compilation error and to attain same results for either case, the respective operators should be overloaded as global functions. They can then be made friend to a class to enable them access private members of that class. Below we repeat our oranges example with overloaded arithmetic operators as friends of the Share class.

#include<iostream>
Using namespace std;

class Share
{
friend ostream& operator<<(ostream&, const Share&);
friend Share operator+(const Share &left, const Share &right);
friend Share operator-(const Share &left, const Share &right);
friend Share operator*(const Share &left, const Share &right);
friend Share operator/(const Share &left, const Share &right);
public:
Share (){}
Share (double convInt)
{
Qty=convInt;
}

private:
double Qty;

};

ostream& operator<<(ostream& print, const Share &s)
{
print<<s.Qty;
return print;
}

Share operator+(const Share &left, const Share &right)
{
return Share(left.Qty+right.Qty);
}

Share operator-(const Share &left, const Share &right)
{
return Share(left.Qty-right.Qty);
}

Share operator*(const Share &left, const Share &right)
{
return Share(left.Qty*right.Qty);
}


Share operator/(const Share &left, const Share &right)
{
return Share(left.Qty/right.Qty);
}


int main()
{
Share OrangeUnits=5.0, QtyPerUnit=20.0;

Share totalOranges=QtyPerUnit*OrangeUnits;

double OtherOranges=100;

Share newTotal=OtherOranges+totalOranges;

Share FormAStudents(20), FormBStudents(30);


Share totalStudents=FormBStudents + FormAStudents;

Share OragesPerStudent=newTotal/totalStudents;

Share NosExtraInB=FormBStudents-FormAStudents; 



cout<<"There are "<< newTotal<<" oranges to be share by "<<totalStudents <<" students \n"
<<"Each student will consume "<<OragesPerStudent<<" Oranges.\n" 
<<"Students in form B will consume "<<NosExtraInB*OragesPerStudent<<" more oranges than those in form A";

return 0;
}

Output:

There are 200 oranges to be share by 50 students 
Each student will consume 4 Oranges.
Students in form B will consume 40 more oranges than those in form A

The definition for class member functions and friend functions for our orange class is almost the same. The difference is that in the first example we used one argument in the overloaded member functions while in the second example two arguments for friend functions were used. This is because binary operators use two arguments when implemented as global functions and one argument if used as member functions. Note that the program still compiles well even when in the expression newTotal=OtherOranges+totalOranges, the variable “OtherOranges” is of double type and is on the left side of the overloaded operator+. We achieved this, because we made the overloaded operator+ function a global function and a friend to our class Share.

The use of an overloaded operator is equivalent to an explicit call to the function which implements it. For example:

operator+(X1, Y1)		// is equivalent to: X1 + Y1

Overloading stream insertion operator (<<) and extraction operator (>>)

The stream insertion operator (<<) and the stream extraction operator (>>) are overloaded as global functions because their leftmost operand is of type ostream &, as in cout << classObject or cin>> classObject. We already have overloaded insertion operator<<as a friend to our “Share” class. As earlier noted, when the right operand is an object of a user-defined class and the leftmost operand has to be an object of another class, that operator must be overloaded as a global function. Overloaded operator functions of these operators are made friends in case they do require access to the private members of the class object being output or input. See the example below.

#include<iostream>
Using namespace std;

class Grades
{
friend ostream&operator<< (ostream&,const Grades&);
friend istream&operator>> (istream&,const Grades&);
int grades;

public:
Grades(int convInt)
:grades(convInt){}
};

ostream&operator<<(ostream &Print,const Grades& Scores)
{
Print<<Scores.grades;
return Print;
}
istream&operator>>(istream &input,const Grades&Scores)
{
input>>Scores.grades;
return input;
}

int main()
{
Grades Maths, Physics, Biology;
cout<<"Enter your grades for Maths, Physics and Biology in that order"<<endl;
//cin>>Maths>>Physics>>Biology;
cout<<"Yous grades are: Maths = "<<Maths<<"%, Physics = "<<Physics<<"%, and Biology = "<<Biology<<"%";
return 0;
}

Output:

Enter your grades for Maths, Physics and Biology in that order
Yous grades are: Maths = 60%, Physics = 50%, and Biology = 65%

Type Conversion

Type conversions are automatic when dealing with built-in data types. For example,

int  Kms =2;
float  Meters;

if we make

Meters = 1000*Kms;

the compiler will automatically first convert kms to float before using its value in the expression assigned to meters. However the compiler does not support automatic type conversion for user defined data types. The programmer has to explicitly define conversion routines. However C++ provides different circumstances of data conversion between incompatible types. We can convert from; basic type to class type, class type to basic type and from one class type to another class type.

Converting from basic type to class type

The example below coverts a basic char type to a School class type. It uses a constructor to build a School type object from a char * type variable. It also uses an overloaded insertion operator(<< ) to print the School type object.

#include<iostream>
Using namespace std;
class School
{
friend ostream &operator<<(ostream&,const School&); 
int length;
char*name;

void setName(const char*);
public:
School(const char* ="");
~School(){delete [] name;}  
};
School::School(const char* schNm)
:length((schNm!=0)?strlen(schNm):0)
{
setName(schNm);
}

void School::setName(const char*StNm)
{
name=new char[length + 1];
if(StNm!=0)
strcpy(name,StNm);
else
name[0]='\0';
}

ostream &operator<<(ostream & Print,const School &nm) // overloaded insertion operator 
{
Print<<nm.name;
return Print;
}

int main()
{
// Calls for the cosntructor are made to set School type obejcts (Teacher,Subject,ItsName) 
 //but after converting from a char type string  
School Teacher("Sam Aine is");
School Subject(" an english teacher at");
School ItsName(" Modern High School");
cout<<Teacher<<Subject<<ItsName<<endl;

return 0;
}

Output:

Sam Aine is an english teacher at Modern High School

The compiler will first convert private data member “name” from char* type to School class type. The School type value is then assigned to the respective object(i.e.Teacher or Subject or ItsName).

The next example converts from basic float type to user-defined convert data type.

#include<iostream>
Using namespace std;
class convert
{
float kms;
float mls;
public:
convert (){}
convert(float k, float ml){kms=k; mls=ml;}
float getKms(){return kms;}
float getMls(){return mls;}
convert (float mtr)
{
kms=mtr/1000;
mls=mtr/1600;
}
};

int main()
{
float meters=3000.0;
convert mt;
mt=meters;
cout<<"There are "<<mt.getKms()<<" kilometers  and "<<mt.getMls()<<" miles in "<<meters<<" meters.";
return 0;
}

Output

There are 3 kilometers and 1.875 miles in 3000 meters.

Converting from class type to basic type

When converting from a class type to a basic type, it is important to note that a constructor function does not support this conversion. Instead an overloaded casting operator operator typename( ) { ……. ( function statements )…..} is used to convert a class type data to a basic type. It is also referred to as conversion function.

#include<iostream>
Using namespace std;
class Age
{

int years;
public:

Age(int ag){years=ag;}

Age operator+(Age &y){return Age(years+ y.years);}  //overloaded operator+

operator int( )  // member function overloaded to convert from user-defined to basic type 
{
 return years;
}
};

int main()
{
Age HerAge2001(20), YearSince(10);
int HerCurrentAge=HerAge2001+YearSince;
 cout<<"She is now "<<HerCurrentAge<<" years old";
return 0;
}

Output:

She is now 30 years old

This function converts user defined Age type to basic int type. The initialization of int type HerCurrentAge with Age type data in expression HerAge2001+YearSince causes a conversion from type Age to type int. The conversion function from class type to basic must be member of the class without a return type. It must not have any arguments, because it uses data member function for which it has direct access. Because HerCurrentAge is a basic type we have been able to print without having to overload the insertion operator.

Conversion functions along with constructors are also known as "cast operators" because they are called when a cast is used. The last example used a cast, to print the value of HerCurrentAge an object of type int converted from HerAge2001+YearSince of type Age. Such a call would be achieved with an explicit conversion as follows cout << (int) HerAge2001+YearSince << endl;

Converting from class type to another class type

Converting from one class type to another class type can be done by either a constructor or a conversion function depending on whether the programmer wants the type-conversion function to be located in the source class or in the destination class. We can use the conversion function of the type

operator destinationType ( ) {…….}

Which converts the class object of which it is a member (source class) to an object type of another class or a built-in type( as we saw in our previous example) . destinationType refers to the destination class. A casting operator function can be used at the source class if a class needs to be converted. The source class coverts and provides the result to the destination class object.

#include<iostream>
Using namespace std;

class School
{

string name;
public:

School(string nm){name=nm;}

operator string( )
{
 return name;
}
};


class Teacher
{

string nameHim;
public:

Teacher (string HisNm){nameHim=HisNm;}

operator School( )
{
 return nameHim;
}

};


int main()
{
Teacher HisName("Sam Aine"); 
School Name("Modern High School"),ItsTeacher=HisName;

cout<<(string)ItsTeacher<<" teaches at "<<(string)Name;
return 0;
}

Output:

Sam Aine teaches at Modern High School

Using the inheritance technique (which are yet to cover), we can also pass the conversation constructor of the source class to the destination class as follows

#include<iostream>
Using namespace std;

class School
{

string name;
public:

School(string nm){name=nm;}

operator string( )
{
 return name;
}
};


class Teacher:public School
{

string nameHim;
public:

Teacher (string HisNm):School(HisNm ){nameHim=HisNm;}

};


int main()
{
Teacher HisName("Sam Aine"); 
School Name("Modern High School"),ItsTeacher=HisName;

cout<<(string)ItsTeacher<<" teaches at "<<(string)Name;
return 0;
}

Output:

Sam Aine teaches at Modern High School

Conversion functions are inherited in derived classes. Conversion operators hide only base-class conversion operators that convert to exactly the same type. Therefore, a user-defined operator int function does not hide a user-defined operator short function in a base class.

Each user-defined conversion function must be explicitly, the compiler attempt to use intermediate types into which an object can be converted. The compiler generates an error if the required conversion causes an ambiguity, i.e. when more than one user-defined conversion is available or when a user-defined conversion and a built-in conversion exist.

One of the disadvantages of user-defined type conversion methods is that, unless they are used sparingly, they can lead to programs whose behaviours can be very difficult to predict. Ambiguity occurs when the compiler has more than one option open to it for applying user-defined type conversion rules, and therefore unable to choose. All such cases are reported as errors by the compiler.

Arrays and Overloaded Operators

Overloading Operator[]

Operator [] can be overloaded to determine whether an argument it receives is within a range. We can overload the [] operator to print an error message if a subscript is out of range or to return the left value array element or a copy of the right value element. To get the lvalue the operator [] is overloaded to return an element of the array as reference so that it can be modified. To get the rvalue the operator [] is overloaded as a constant so that it returns a copy of the appropriate element of the array. Follow the example below;

#include<iostream>
Using namespace std;

 
class grades
{
friend ostream &operator<<(ostream &,const grades&);

public:
grades(int=15);
grades(grades&);
~grades();

int &operator[](int );
int operator[](int )const;
private:

int studNo;
int *gradePtr;
};

grades::grades(int studentNo)
{
studNo=studentNo>0?studentNo:15;

gradePtr=new int[studNo];

for (int i=0; i<studNo; i++)
gradePtr[i]=0;
}

grades::~grades(){delete [] gradePtr;}

int &grades::operator[](int subscpt)     //overloader operator[] function which returns a lvalue reference 
{
if (subscpt<0 || subscpt>=studNo)
{
cerr<<"Error: The subscript "<<subscpt<<" is out of range"<<endl;
 exit(1);
}
return gradePtr[subscpt];
}

int grades::operator[](int subscpt) const     // overloader operator[] function that returns a rvalue  
{
if (subscpt<0 || subscpt>=studNo)
{
cerr<<"Error: The subscript "<<subscpt<<" is out of range"<<endl;
 exit(1);
}
return gradePtr[subscpt];
}

ostream &operator<<(ostream &print, const grades& arr)
{
for (int i=0; i<arr.studNo; i++)
print<<setw(4)<<arr.gradePtr[i];

return print;
}


int main()
{
grades students(7);
students[0]=60;
students[1]=40;
students[2]=55;
students[3]=50;
students[4]=60;
students[5]=70;
students[6]=70;

cout<<"The scores of the students are: \n"<<students;
cout<<endl;
cout<<"The array element in index 1 is "<<students[1];  //students[1] calls overloaded operator[] function that returns a rvalue 
return 0;
}

Output:

The scores of the students are: 
  60  40  55  50  60  70  70

The array element in index 1 is 40

Overloaded Insertion and Extraction Operators in Arrays

The operators << and >> can be overloaded as friends of the class. In our example of grades array above, we overloaded the insertion operator (<<). This function outputs directly grades array’s elements pointed to by gradePtr as indicated by the size. When the compiler encounters <<tt> cout<<students,it invokes a function call operator<<(cout,students).

The extraction operator is overloaded in the same way input directly into the array. When the compiler encounters <<tt> cin<<students,it invokes a function call operator<<(cin,students).

The overloaded insertion and extraction operators return a reference to enable cascaded output and input respectively.

Overloaded Assignment Operators= and Arrays

Objects can be assigned other objects of the same class with the use of the overloaded operator= function. The prototype of the overloaded assignment function is written in form of objName &operator = (objName &). Operator = is overloaded as a member, and not as a global function. Using our glades class above, the example below can be included to overload the assignment operator.
const grades &grades::operator=(const grades &copyTo)
{
if(&copyTo!=this)
{
if (studNo !=copyTo.studNo)
{
delete []gradePtr;
grSize=copyTo.studNo;
gradePtr = new int[grSize];
}
for(int i=0; i<studNo; i++)
gradePtr[i] = copyTo.gradePtr[i];
}
return *this;  // a reference is returned to allow for cascading assignment 
}

The function tests for self assignment with &copyTo!=this and skips execution if the condition is true and if not true it checks to see whether the sizes of the two arrays are identical. If the sizes are not identical, a the left object is reallocated to avoid memory leak and re set with new size. Then the ‘for’ statement copies the array elements from the right array into the left array. Self-assignment test is important to avoid operator= function from deleting the dynamic memory of the left side Array object which would leave gradePtr pointing to a non-existing memory. To avoid a logic error an overloaded assignment operator and a copy constructor should be provided if objects of the class contain pointers to dynamically allocated memory.

The overloaded operator= function enables us to assign grades objects. If students1 and students2 are grades objects, we can perform the assignment as follow

	students1= students2; 

When the compiler encounters such an expression, it will automatically call the overloaded operator= function to perform the assignment procedure. The compiler invokes member function operator= with the call

students1.operator=( students2)

Overloading a Function Call Operator ()

It possible to overload operator () to provide alternate array-subscript notation. The function call operator is overloaded as a non-static member function and is used only when the "function name" is an object of class String. Using our initial example of the School class type we can overload the operator () as follows ;

			School School::operator()( int index, int subLeng ) const
  			
			{
    			 // check if the substring length is in the range

   			 	 if ( index i< 0 || index >= length || subLeng i< 0 )
      			 	 return ""; 

        		// determine length of substring
  
				int len;

     				if ( ( subLeng == 0 ) || ( index + subLeng i> length ) )
     					len = length - index; 
    				else
   					len = subLeng;

    			// temporary array for substring 

     			char *tempPtr = new char[ len + 1 ];

    			// copy substring into char array 
   			strncpy( tempPtr, &name[ index ], len );
     				tempPtr[ len ] = '\0';

     			// create temporary String object containing the substring
     				School newSchool;( tempPtr );
     				delete [] tempPtr; // delete temporary array
     				return newSchool; // return copy of the temporary String
			} // end function operator()
			}

The overloaded function call operator is used to select a substring from a School object. The index and subLeng parameters specify the start location and the length of the substring being selected from the School object. The function check whether the start location is out of range or if the substring length is less than zero and if so it returns an empty School object. If the start location is 0 or it sum with the substring length is greater than the length of original School object, the length of substring is reset to fall within the length of the original object. Otherwise the length of the substring is used to allocate it memory and then use a temporally object to copy the substring into the new School object.

When the the compiler sees an expression such as newSchool( 1, 5 ), it will generate the member-function call newSchool.operator()( 1, 5 ). The overloaded function call operator will return a copy of the temporally School object.

Overloading Inequality and equality operators ==, > and <

Inequality operators such as >, < and quality operators can be overloaded to compare objects of the same class. They generally have a similar definition. Let us consider our ‘grades’ class example. We can use that example to overload the equality operator as follows

			bool grades::operator==(const grades &right)const
			{
				if(grSize!=right.grSize)
				return false;

				for ( int i = 0; i < grSize; i++ )
				if(grPtr[i]!=right.grPtr[i])
				return false;

				return true;
			}

The overloaded quality operator == function tests for whether size of the left side is equal to the right or whether the elements of the array are the same and then returns false for each case. Otherwise the function returns true indicating that the left object is equal to the right object.

Operators !=, >, <, <= and >= operators are implemented in the same way like the above operator== function. Below is another example for overloading the greater than Operator>

			bool grades::Operator>(const grades &right)const
			{
				if(grSize==right.grSize)
				return false;

			if(grSize<right.grSize)
			return false;

			return true;
			}

When the compiler sees a statement grades1 == grades2, or grades1 > grades2, a respective member-function call grade1.operator==( grade2 ) or grade1.Operator>( grade2 ) is made

Overloading Postfix and Prefix Increment and Decrement Operator++ and --

The postfix and prefix increment and decrement operators can be overloaded to increase or decrease the class object by 1. Both the prefix and postfix operators can be overloaded in a similar manner accept for their signatures.

Being a unary operator, the prefix operator is overloaded as a member function with no argument or as global function with only one argument. The prefix operator returns the object by value. To increment Time object H by one we write the prototype for the overloaded increment member function as

				Time &operator++();

When the compiler sees the statement ++H, it will generate the member function call

				H.operator++();

The prototype for the overloaded global function is written as follows

				Time &operator++(Time&);

When the compiler sees the statement ++H, it will generate the global function call

				operator++(H);

The signatures for the overloaded postfix operator must include a “dummy value” to enable the compiler distinguish differentiate it from the prefix operator. The postfix operator returns the object by reference because it typically returns are a temporary that contains the value of the object before the increment occurred.

The prototype for the overloaded postfix increment member function is written as follows

				Time operator++( int);

When the compiler sees the statement H++, it will generate the member function call

				operator++(H);

The prototype for the overloaded postfix increment global function is written as follows

				Time operator++(Time, int);

When the compiler sees the statement H++, it will generate the global function call

				operator++(H, 0);

The argument 0 is the dummy value that compiler uses to distinguish between the prefix and postfix decrement or increment operator implemented as global function.

Below is an example that overloads the prefix decrement operator as a member function and post fix increment operator as global function.

		#include<iostream>
		using namespace std;

		class OneMore
		{
			friend OneMore operator++(OneMore&, int);  //Overloaded postfix ++ global function 
			friend ostream &operator<<(ostream&, const OneMore&);
		int x;
		public:
			OneMore(int X):x(X){}
			OneMore &operator--() // overloaded prefix – member function 
		{
			--x;
			return *this;
		}
		};
		
		OneMore operator++(OneMore &add, int)
		{
			OneMore temp=add.x;
			add.x++;
			return temp;
		}
		ostream &operator<<(ostream&Output, const OneMore& add)
		{
			Output<<add.x;
			return Output;
		}

		int main()
		{
			OneMore FirstNo(2);

			OneMore SecondNo=--FirstNo;

			cout<<"First Number 2 after decrement is "<< SecondNo<<endl;
			SecondNo++;
			cout<<"It is again incremented to "<<SecondNo;
			return 0;
		}

Output:

		First Number 2 after dicrement is 1
		It is again incremented to 2
PREV:Constructors and Distructors NEXT:Introduction to Inheritance