Tuesday 23 October 2012

Operator Overloading in C++


Operator Overloading
 Operator Overloading
Structure
6.1 Introduction
6.2 Operator Overloading in C++
Self Assessment Questions
6.3 Overloading Unary Operators
Self Assessment Questions
6.4 Overloading binary operators
Self Assessment Questions
Summary
Terminal Questions
6.1 Introduction
This unit has the following objectives
· To learn how C++ supports operator overloading
· To learn to overload different types of unary and binary operators
· To understand limitations of operator overloading
6.2 Operator Overloading in C++
Operator overloading is an interesting feature of C++ that allows programmers to specify how various arithmetic, relational and many other operators work with user defined datatypes or classes. It provides a flexible way to work with classes and can make program code look obvious. In the unit 5, we had written an add function for the class distance. To perform addition of two distance objects we used a call d3.add(d1,d2). Instead of such statements it would be more clear if we could use statements like d3=d1+d2. This is possible only if we inform compiler about how + operator works with distance class. This is exactly what operator overloading feature in C++ does. It helps to use the default operators with the user defined objects for making the code simpler.
However there are several problems with operator overloading which you should be aware of. When using operator overloading, the operator should perform only the most obvious function. Otherwise it will lead to more confusion. If you are overloading + operator for distance class it should add two distance objects, and should not do something else. However some syntactical characteristics of operators cannot be changed even if you want to. For example, you cannot overload a binary operator to be a unary operator and vice versa.
Several operators such as dot operator, scope resolution (::) operator, conditional operator (?:) etc cannot be overloaded.
Therefore operator overloading should be used for a class where it is required to perform obvious functions with the default operators and there can be no other meaning for the same.
Self Assessment Questions
1. Operator overloading feature helps to change the functionality of operators with any datatype. True/False
2. You can overload all operators in C++. True/False
3. It is necessary to overload operators for all classes. True/False
6.3 Overloading Unary Operators
We have seen that unary operators are those operators which work on one operator. Some of the unary operators are ++, --, and minus (-).
Operator overloading works similar to any member function of a class. But it is not invoked using dot operator. Just like member function the operator has a return value and takes arguments. It is invoked by the operand which uses it. In case of overloading of unary operators, the calling operand can be either left or right of the operator like in case of increment and decrement operators. While defining the operator functionality for the class the keyword operator is used. Let us overload the increment operator for a class.
//unary.cpp
# include <iostream.h>
class counter
{ unsigned int count;
public:
counter()
{count=0;}
int getcount()
{return count;}
void operator ++()
{ count++;}
};
void main()
{ counter c1;
c1++;
++c1;
cout<<c1.getcount();
}
In the above example, the operator ++ is defined to return void and take no arguments. All unary operators do not take no arguments as it operates on only one operand and that operand itself invokes the operator. Therefore the operand is sent by default. However the above implementation cannot be used in statements such as c2=c1++; where c1 and c2 are counter variables. This is because the operator ++ returns void which makes an counter variable being assigned void value. To overcome this, you can make the operator return an counter variable as shown below
//incremnt.cpp
# include <iostream.h>
class counter
{ unsigned int count;
public:
counter()
{count=0;}
counter(int c)
{count=c;}
int getcount()
{return count;}
counter operator ++()
{ count++;
return counter(count);}
};
void main()
{ counter c1,c2;
c1++;
c2=++c1;
cout<<c1.getcount()<<endl;
cout<<c2.getcount();
}
In the above implementation, we are returning the counter variable without creating a variable. This is enabled by including constructor with one argument. When return counter(count) is specified, value stored in the variable count of the invoking object is passed to the constructor and a nameless object is created which is initialized to the value stored in the count and returned to the calling program. One argument constructor is used in this case.
Unary operators like increment and decrement operators cannot be completely duplicated. As the compiler cannot differentiate between post and pre increment/decrement operators. This one of the limitation of overloading unary operators.
Self Assessment Questions
1. Unary operators are implemented with _____ arguments.
2. Unary operators should have return value as ________.
3. Unary operators overloaded for the class can differentiate between post and pre operators. True/False
6.4 Overloading binary operators
Binary operators are those that work on two operands. Arithmetic operators like + , * etc and relational operators like <, > etc are some examples of binary operators. Overloading binary operators is different from overloading unary operators mainly in terms of the way it is invoked and arguments passed. When you overload a binary operator, the operand to the left of the operator calls the operator and the operand to the right of the operator is passed as an argument.
The following example shows the overloaded + operator for the class distance.
# include<iostream.h>
class distance
{ private:
int feet, inches;
public:
distance()
{feet=0; inches=0;}
distance(int f)
{feet=f; inches=0;}
distance(int f, int i)
{feet=f;inches=i;}
void display()
{cout<<feet <<" "<<inches<<endl;}
distance operator + (distance d1)
{ int f = feet+d1.feet;
int i = inches+d1.inches;
return distance(f,i);}
};
void main()
{
distance d1(2,5), d2(1,4),d3, d4;
d3=d1+d2;
d3.display();
d4=d3+2;
d4.display();
}
In the above program, the operator + is overloaded. The declaration shows that a distance object is passed as an argument and an distance object is returned. In the main program, the statement d3=d1+d2 invokes the + operator where d1,d2,d3 are distance objects. The object d1 calls the + operator (left operand) and d2 is passed as an argument (right operand) and after the two objects are added they are returned to the main program which is stored in the d3 object.
In the second statement, d4=d3+2, d3 invokes the + operator and 2 is passed as an argument. The one argument constructor is invoked to convert 2 (integer datatype) into distance object.
However the above implementation has a limitation. The compiler will not understand how to handle statements like d2=10+d1 where the left operand which calls the operand is not a distance object. This can be however handled through a concept known as friend functions. By declaring the operator + as a friend you can accomplish it to handle multiple datatypes. Friend functions are external functions that can access the private data members of a class. However, the class definition should declare the function as a friend. They can act as a bridge between two classes or in other words they can be used when a single function has to operate on multiple datatypes. A function is made friend by just prefixing the keyword friend in the function declaration within the class definition.
# include<iostream.h>
class distance
{ private:
int feet, inches;
public:
distance()
{feet=0; inches=0;}
distance(int f)
{feet=f; inches=0;}
distance(int f, int i)
{feet=f;inches=i;}
void display()
{cout<<feet <<" "<<inches<<endl;}
friend distance operator + (distance, distance);
};
distance operator + (distance d1, distance d2)
{ int f = d1.feet+d2.feet;
int i = d1.inches+d2.inches;
return distance(f,i);}
void main()
{
distance d1(2,5), d2;
d2=10+d1;
d2.display();
}
Let us see another type of binary operator < and learn how relational operators can be overloaded. In case of relational operators also there can be one argument overloading or two argument overloading (using friend functions). However, the return value should be integer (0 or 1) indicating true or false or some compilers support to create boolean datatypes.
The following program implements the program for < relational operator overloading for the distance class.
# include<iostream.h>
class distance
{ private:
int feet, inches;
public:
distance()
{feet=0; inches=0;}
distance(int f)
{feet=f; inches=0;}
distance(int f, int i)
{feet=f;inches=i;}
void display();
void getdata();
int operator < (distance d1)
{ if (feet<d1.feet)
return 1;
else if (feet==d1.feet) && (inches<d1.inches)
return 1;
else
return 0;
}
};
void distance :: display()
{cout<<feet <<" "<<inches<<endl;}
void distance :: getdata()
{ cout<<”Enter distance in feet and inches”;
cin>>feet >>inches;}
void main()
{
distance d1,d2;
d1.getdata();
d2.getdata();
if (d1<d2)
cout<<d1.display() << “is smaller”;
else
cout<<d2.display()<< “ is smaller”;
}
In the above program the d1 object invokes the operator < and d2 is passed as an argument. The return value is either 0 or 1 which indicates false or true respectively. Certain compilers support boolean datatype which can be alternatively used instead of integer. The above program also implements display and getdata member functions differently. The member functions are declared inside the class but are defined outside the class. But to specify that the member function belongs to the distance class, the class name is included along with the function name separated by the scope resolution operator (::).
Self Assessment Questions
1. Member functions of a class can be defined outside the class using ________ operator along with the class name.
2. _________ functions are external functions that can access private data members of a class.
3. Overloaded relational binary operators should return _________
4. Left operand calls the operator in case of binary operator. True/False.
Summary
Operator overloading allows to define new meaning for normal C++ operators and specifies how it can be used with the user defined classes. Overloading should be used only to imply default meanings to avoid confusion in its usage. Not all operators can be overloaded.
Terminal Questions
1. Create a class string which stores a string value. Overload ++ operator which converts the characters of the string to uppercase (toupper library function of ctype.h can be used).
2. When you overload an arithmetic assignment operator, the result
a. Goes in the object to the right of the operator
b. Goes in the object to the left of the operator
c. Goes in the object of which the operator is a member
d. Must be returned
3. Overload += operator for the string class which should allow statements like s1+=s2. This should concatenate strings s1 and s2 and store the result in s1.
4. The compiler will not show any error is you overload the * operator to perform division. True/False
Answers to SAQs in 6.2
1. False
2. False
3. False
Answers to SAQs in 6.3
1. No
2. Same as class datatype
3. False
Answers to SAQs in 6.4
1. scope resolution operator
2. Friend Function
3. Integer or Boolean values
4. True
Answers to TQs
1. //string.cpp
# include<iostream.h>
# include<ctype.h>
# include<string.h>
# include<conio.h>
class string
{ char str[25];
public:
string()
{ strcpy(str, "");}
string(char ch[])
{ strcpy(str, ch);}
void display()
{ cout<<str;}
string operator ++()
{string temp;
int i;
for(i=0;str[i]!='';i++)
temp.str[i]=toupper(str[i]);
temp.str[i]='';
return temp;
}
};
void main()
{ clrscr();
string s1="hello", s2;
s2=s1++;
s2.display();
getch();
}
2. must be returned
3. //stringar.cpp
# include<iostream.h>
# include<ctype.h>
# include<string.h>
# include<conio.h>
class string
{ char str[25];
public:
string()
{ strcpy(str, "");}
string(char ch[])
{ strcpy(str, ch);}
void display()
{ cout<<str;}
void operator +=(string s2)
{int i,l,j;
l=strlen(str);
for(i=l,j=0; s2.str[j]!=''; i++,j++)
str[i]=s2.str[j];
str[i]='';
}
};
void main()
{ clrscr();
string s1="hello", s2="world";
s1+=s2;
s1.display();
getch();
}
  • 0 likes

3 comments: