12 Operator Overloading with friend functions
Jyoti Pareek
Introduction
We have seen in the earlier module that Operators can also be overloaded for subtracting objects of other data type from the object of the class. For example we saw minus (–) operator can also be overloaded to make the following statement work.
Time_difference = current_time – 5;
To make this work, we can overload minus (–) operator as member function as follows:
Time operator – (int h)
{
Time diff;
diff.hours = hours – h;
diff.minutes = minutes;
diff.seconds = seconds;
return diff;
}
What if we want something like following to work for us?
Time_difference = 5 – current_time;
As we discussed earlier in case of operator overloading first operand invokes the operator function and second one is passed as argument. But in the above statement first operand is integer constant, which cannot invoke the member function of Time class. Therefore minus (-) operator cannot be overloaded as member function to achieve the same.
Then how do we make it work?
In this scenario friend functions can be of help to us. As friend function is not a member of class, it does not require object for its invocation. Therefore the first argument of operator need not be object of the class for which operator is being overloaded. However at least one of the operands must be the object of the class for which operator is being overloaded. Both Unary as well as binary operators can be overloaded through friend function.
Overloading Binary Operator Using friend function
The operator can also be overloaded through friend function. When binary operator is overloaded as member function, the first operand being invoking object is implicitly passed in operator function. Therefore only one argument that is the second operand is to be passed to the operator function. Whereas friend function being independent function requires both the operands to be passed as argument.
The syntax for declaring function in class, for overloading binary operator through friend function is as follows:
friend return_type operator operator_to_be_overloaded (argument1, argument2);
Here at least one of the arguments has to be the object of class for which the operator is overloaded. We can overload minus(-) operator for Time class as follows
friend Time operator- ( int x , Time t )
class Time
{
private:
int second;
int minute;
int hour;
public:
……….
……….
……….
friend Time operator – (int h, Time t);
………..
………..
};
Time operator – ( int h , Time t )
{
Time diff;
diff.hours | = t.hours – h; | ||
diff.minutes | = | t.minutes; | |
diff.seconds | = | t.seconds; | |
return diff; | |||
} | |||
Dr. Jyoti Pareek | 2 | Object Oriented Concepts & Programming |
As friend functions are independent functions and not the member of any class, they do not need any object for their invocation. Hence in case of overloading through friend functions first operator need not be object of class. Addition of above function to our Time class will make the following statement work
Time_difference = 5 – current_time;
Plus (+) operator for adding two Time objects can be defined as follows:
private:
int second;
int minute;
int hour;
public:
……….
……….
……….
friend Time operator + (Time t1, Time t2);
………..
………..
};
Time operator+(Time t1, Time t2)
{
Time time;
time.seconds=t1.seconds + t2.seconds ;
time.minute= time.seconds / 60 ;
time.seconds = time.seconds % 60 ;
time.minute =t1.minute + t2.minute + time.minute; time.hour= time.minute / 60 ; time.minute= time.minute % 60 ;
time.hour= t1.hour + t2.hour +time.hour;
return time;
}
Overloading unary operator through friend function
Syntax for overloading Unary operator as member function is as follows:
return_type operator operator_to_be_overloaded ( );
Here unary operator has only one operand, which will be the invoking object, hence passed implicitly in the function. Therefore it does not require any argument. If unary operator is overloaded using friend function which is not invoked on any object, the operand needs to be passed as argument. The syntax for declaring function in class for overloading unary operator using friend function is as follows:
friend return_type operator operator_to_be_overloaded (object);
Let us overload increment (++) operator, which is a unary operator for Time class. C++ provides increment (++) and decrement (–) operators in two flavors – Postfix version and Prefix version
Time now;
now++;
++now;
If we want both the versions to be overloaded, the prototype for both operator functions will turn out to be identical. It will result into ambiguous situation for the compiler. To resolve this C++ compiler allows us to define different prototype for both the versions. We can overload prefix version of increment (++) operator using friend function as follows:
friend Time operator++ (Time &t);
and postfix version of increment operator can be overloaded as
friend Time operator++ (Time &t, int x);
Here x is a dummy argument, which has no role in the function and has been defined only to distinguish between infix and postfix versions of increment(++) operator.
class Time
{
private:
int second;
int minute;
int hour;
public:
……….
………
……….
friend void operator ++ (Time &t);
friend void operator ++ (Time &t, int x);
………..
………..
};
// Prefix Version
void operator ++(Time &t)
{
//increment seconds
t.seconds++;
if(t.seconds==60)
{
t.seconds=0;
t.minute++;
if(t.minute==60)
{
t.minute=0;
t.hour++;
}
}
}
// Postfix version
void operator ++(Time &t, int x)
{
//increment seconds
t.seconds++ ;
if(t.seconds==60)
{
t.seconds=0;
t.minute++;
if(t.minute==60)
{
t.minute=0;
t.hour++;
}
}
}
Notice here time object is passed as reference, because if we pass it by value change in the object will not be reflected in calling function. Both the versions for decrement (–) operator can also be overloaded in the similar fashion.
Operators that cannot be overloaded using friend functions
We have seen operators can be overloaded using member function as well as friend function. However there are some operators which can be overloaded as member function but cannot be overloaded as friend function. List of operators which cannot be overloaded using friend function is given below:
1. Assignment operator =
2. Function call operator ( )
3. Array subscript operator [ ]
4. Access to class member using pointer to object operator ->
What can be the reason behind these operators being not allowed to be overloaded using friend function?
Let us take the example of assignment operator =. If this operator is allowed to be overloaded using friend function, it is possible to define following overloaded function
friend void operator = (int x, time T);
Once we define the above function the following statement becomes valid
5 = now;
Can this be allowed? No, this cannot be allowed as the left hand side operand of assignment (=) operator must be l-value, which cannot be a constant. Since programmer may attempt something of this type, the overloading of assignment (=) operator through friend function is prohibited. Every operator which cannot be overloaded using friend function has such compelling reasons for their prohibition. Try to discover reasons for prohibition of each operator by yourself or explore resources for the same.
Overloading insertion (>>) and extraction (<<) operators
If we want to read and write time object through cin and cout objects as we read object of any standard data type, we can overload insertion (>>) and extraction (<<) operators for our class. Let us have a look at the syntax of I/O statement that we would want to work for our Time class
Time now;
cin >> now;
Here cin is an object of predefined stream class istream, and now is an object of our Time class. As we know, to overload operator using member function the first operand has to be the object of the class for which we are overloading the function. But here the first operand is object of istream class which we cannot modify. Hence this operator in Time class cannot be overloaded as member function. We will have to overload it as friend function.
class Time
{
private:
int second;
int minute;
int hour;
public:
……….
……….
……….
friend ostream & operator << (ostream &, Time &t); friend istream & operator >> (istream &, Time &t);
………..
………..
};
ostream & operator<<(ostream &out, Time &t)
{
cout <<t.hour<<“:”<< t.minute<<“:”<< t.seconds; return out;
}
istream & operator >> (istream &in, Time &t)
{
cout<<“\nEnter hour, min and second:\n” ;
in >> t.hour;
in >> t.minute;
in >> t.second;
return in;
}
By now you must have understood how the statements like the one given below work
int x;
float y;
cin >> x;
cin >> y;
cout >> x;
cout << y;
You guessed it right, these statements works because insertion(>>) and extraction (<<) operators have been appropriately overloaded in istream and ostream classes respectively. Prototype of these functions in istream and ostream classes respectively would be
istream & operator>> (istream &,int );
istream & operator>> (istream &,float );
ostream & operator<<(ostream &, int );
ostream & operator<<(ostream &, float );
Friend function as such violates the data hiding; therefore its use must be discouraged. For the same reason overloading operators using friend function also must be discouraged. However as we have seen in this session there are certain cases where operator cannot be overloaded as member function, in such cases overloading operator is possible using friend function only. We can conclude that we should overload the operator using friend function only when it is not possible to overload operator as member function.
Restrictions on Overloading
What we cannot do through operator overloading
1) We cannot change the precedence and associativity of operator we are overloading.
2) We cannot add new operators. Only those operators which are provided by the language can be overloaded.
3) Except ( ), no other operator function can have default arguments.
4) We cannot change the number of arguments that an operator can take.
5) When we overload an operator for new task, its earlier meaning with other data type remains intact, it cannot be changed.
Summary
By means of operator overloading we can use operators provided by the language with the user defined data types to perform arithmetic, logical or other operations. Operator overloading is not mandatory for any programming language. As discussed before many object oriented programming languages including JAVA do not provide operator overloading. We can do without operator overloading but operator overloading provides significant advantages in terms of making code easy to read and manage (a very important quality factor for any code).
We have seen that operators can be overloaded using member as well as friend functions. As friend functions are independent functions they are not invoked on object. Therefore if we overload operator as friend function, all the operands are to be passed as argument. As friend functions violate data hiding, we should overload operator through functions only when overloading operator as member function is not possible.
Operator overloading will yield full advantage when the new definition added to the operator is intuitive resulting into simple and easy to understand code.
Following is the complete C++ program for overloading operators as friend functions as discussed above.
you can view video on Operator Overloading with friend functions |
Additional References
1) Stanley Lippmann, “C++ Primer”, Pearson Education.
2) Bjarne Stroustrup, “The C++ Programming Language”, Pearson Education.
3) Scott Mayer, “Effective C++”, Addison Wesley.
4) Bhushan Trivedi , Programming with ANSI C++, 2/e , Oxford University Press.
5) Yashavant P. Kanetkar “Let Us C++” , Bpb Publications.
6) Abhiram G. Ranade, “An Introduction to Programming through C++” , McGraw Hill
7) Ellis and B. Stroustrup “Annotated C++ Reference Manual”, http://www.stroustrup.com/arm.html
8) Herbert Schildt, “Complete Reference C++”, McGraw Hill Publications.
9) Ashok Kamthane, “Object Oriented Programming with ANSI and Turbo C++”, Pearson Education
10) E Balaguruswami, “Object Oriented Programming With C++”, Tata McGraw Hill
11) “C++ FAQs”, Pearson Education.