TechCSE: Operator Overloading

Sunday, 30 October 2011

Operator Overloading


Introduction
Operator overloading is another example of polymorphism in C++. Operator overloading extends the
overloading concept to operators, letting you assign multiple meanings to C++ operators. Actually, many C++
(and C) operators already are overloaded. For example, the * operator, when applied to an address, yields the
value stored at that address. But applying * to two numbers yields the product of the values. C++ uses the
number and type of operands to decide which action to take.
In C++, you can overload most operators so that they perform special operations relative to classes that you
create.
Overloaded operators often can make code look more natural. For example, adding two arrays is usually done
by the following for loop:
for (int i = 0; i < 20; i++)
total[i] = physics[i] + chemistry[i]; // add element by element
But in C++, you can define a class that represents arrays and that overloads the + operator so that you can do
this:
total = physics + chemistry;
// add two array objects
Creating a Member Operator Function:
You overload operators by creating operator functions. An operator function defines the operations that the
overloaded operator will perform relative to the class upon which it will work. An operator function is created
using the keyword operator. Operator functions can be either members or nonmembers of a class. Nonmember
operator functions are friend functions of the class.
A member operator function takes this general form:
ret-type class-name::operator# (arg-list)
{
// operations
}
Often, operator functions return an object of the class they operate on, but ret-type can be any valid type. The #
is a placeholder. When you create an operator function, substitute the operator for the #. For example, if you are
overloading the / operator, use operator/( ). Again, operator+( ) overloads the + operator (# is +) and
operator*( ) overloads the * operator (# is *). When you are overloading a unary operator, arg-list will be
empty. When you are overloading binary operators, arg-list will contain one parameter.
Here is a simple first example of operator overloading.
class Location
{
int longitude, latitude;
public:
Location() {}
Location(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show ( )
{
cout << longitude << ” “;
cout << latitude << “\n”;
}
Location operator+(Location op2);
};
// Overload + for Location.
Location Location:: operator+(Location op2)
{
Location temp;
temp.longitude = op2.longitude + longitude;
temp.latitude = op2.latitude + latitude;
return temp;
}
int main()
{
Location ob1(10, 20), ob2( 5, 30), ob3;
ob1.show(); // displays 10 20
ob2.show(); // displays 5 30
ob3 = ob1 + ob2;
ob3.show(); // displays 15 50
return 0;
}
Note 1: operator+ ( ) has only one parameter even though it overloads the binary + operator because the
operand on the left side of the + is passed implicitly to the function through the this pointer. The operand on the
right is passed in the parameter op2. When binary operators are overloaded, it is the object on the left that
generates the call to the operator function. The operator function is called as:
ob3 = ob1. operator+ (ob2);
Note 2It is common for an overloaded operator function to return an object of the class it operates upon. By
doing so, it allows the operator to be used in larger expressions. For example, if the operator+ ( ) function
returned some other type, this expression would not have been valid:
ob3 = ob1 + ob2;
or, ob4 = ob1 + ob2 + ob3;
In order for the sum of ob1 and ob2 to be assigned to ob1, the outcome of that operation must be an object of
type Location.
Note 3: Having operator+ ( ) return an object of type Location makes possible the following statement:
(ob1+ob2).show ( ); // displays outcome of ob1+ob2
In this situation, ob1+ob2 generates a temporary object that ceases to exist after the call to show ( ) terminates.
Note 4: The return value, however, cannot be a reference. The reason is that the function creates a new
Location object (temp) representing the sum of the other two Location objects. Returning the object, as this
code does, creates a copy of the object that the calling function can use. If the return type were Location &,
however, the reference would be to the temp object. But the temp object is a local variable and is destroyed
when the function terminates, so the reference would be a reference to a nonexistent object. Using a Location
return type, however, means the program constructs a copy of temp before destroying it, and the calling
function gets the copy.
Note 5: The operator+ ( ) function does not modify either operand. Because the traditional use of the + operator
does not modify either operand, it makes sense for the overloaded version not to do so either. (For example, 5+7
yields 12, but neither 5 nor 7 is changed.)
The next program adds two additional overloaded operators to the Location class: the – operator and the = operator.
class Location {
int longitude, latitude;
public:
Location() {} // needed to construct temporaries
Location(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << ” “;
cout << latitude << “\n”;
}
Location operator-(Location op2);
Location operator=(Location op2);
};
// Overload – for Location.
Location Location::operator-(Location op2)
{
Location temp;
// notice order of operands
temp.longitude = longitude – op2.longitude;
temp.latitude = latitude – op2.latitude;
return temp;
}
// Overload asignment for Location.
Location Location::operator=(Location op2)
{
longitude = op2.longitude;
latitude = op2.latitude;
return *this; // i.e., return object that generated call
}
int main()
{
Location ob1(10, 20), ob2( 5, 30), ob3(90, 90);
ob1.show();
ob2.show();
ob3 = ob1 – ob2;
ob3.show();
ob1 = ob2 = ob3; // multiple assignment
ob1.show(); // displays 90 90
ob2.show(); // displays 90 90
return 0;
}
Note 1: Notice the order of the operands in the subtraction in the operator– ( ) function. In keeping with the
meaning of subtraction, the operand on the right side of the minus sign is subtracted from the operand on the
left. Because it is the object on the left that generates the call to the operator– ( ) function, op2′s data must be
subtracted from the data pointed to by this.
Note 2: In C++, if the = is not overloaded, a default assignment operation is created automatically for any class
you define. The default assignment is simply a member-by-member, bitwise copy. By overloading the =, you
can define explicitly what the assignment does relative to a class. In this example, the overloaded = does exactly
the same thing as the default, but in other situations, it could perform other operations. Notice that the
operator= ( ) function returns *this, which is the object that generated the call. This arrangement is necessary if
you want to be able to use multiple assignment operations such as this:
ob1 = ob2 = ob3; // multiple assignment

Overloading the Prefix and Postfix Forms of the Increment and Decrement Operators :
C++ allows you to explicitly create separate prefix and postfix versions of increment or decrement operators. To
accomplish this, you must define two versions of the operator++ ( ) function. The prefix one is declared as:
Location operator++ ( )
The postfix one is declared as: Location operator++ (int x);
If the ++ precedes its operand, the operator++ ( ) function is called. If the ++ follows its operand, the
operator++ (int x) is called and x has the value zero. Here we don’t need to supply the value of x, it just to
differentiate between the two versions of the same function.
class Location {
int longitude, latitude;
public:
Location() {} // needed to construct temporaries
Location(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << ” “;
cout << latitude << “\n”;
}
Location operator++ ( );
//prefix version of ++
Location operator++ (int);
// postfix version of ++
};
// Overload prefix ++ for Location.
Location Location::operator++ ( )
{
longitude++;
latitude++;
return *this;
}
// Overload postfix ++ for Location.
Location Location::operator++ ( int x)
{
Location obj;
obj.longitude = longitude;
obj.latitude = latitude;
longitude++;
latitude++;
return obj;
}
int main()
{
Location ob1(10, 20), ob2( 5, 30), ob3(90, 90);
ob1.show();
ob2.show();
ob1 = ++ob2;
ob1.show ( );
TechCSE 5
Operator Overloading
ob2.show ( )
ob1 = ob2++;
ob1.show();
ob2.show();
return 0;
}
Similarly, we can overload the prefix and postfix versions of the unary decrement (–)operator.
Overloading the Shorthand Operators
You can overload any of C++’s “shorthand” operators, such as +=, –=, and the like. For example, this function
overloads += relative to Location:
Location Location::operator+=(Location op2)
{
longitude = op2.longitude + longitude;
latitude = op2.latitude + latitude;
return *this;
}
Operator Overloading Restrictions
There are some restrictions that apply to operator overloading.
1. You cannot alter the precedence of an operator.
2. No new operator can be created. For example, we cannot write an operator function for @, because
C++ doesn’t have @ as an operator.
3. Operator functions cannot have default arguments.
4. Technically you are free to perform any activity inside an operator function. For example, if you want
to overload the + operator in such a way that it writes I like C++ 10 times to a disk file, you can do so.
However, when you stray significantly from the normal meaning of an operator, you run the risk of
dangerously destructuring your program.
5. Except for the = operator, operator functions are inherited by any derived class. However, a derived
class has to redefine the inherited operator functions to make them useful because operators are
overloaded for whole object not a part of it.
6. We can overload around 40 different operators in C++ but overloading only the arithmetic and
relational operators proves to be useful.
7. The overloaded operator must have at least one operand that is a user-defined type. This prevents you
from overloading operators for the standard types. Thus, you can’t redefine the minus operator (-) so
that it yields the sum of two double values instead of their difference. This restriction preserves
program sanity, although it may hinder creative accounting.
8. You cannot change the number of operands that an operator takes. You can’t use an operator in a
manner that violates the syntax rules for the original operator. For example, you can’t overload the
modulus operator (%) so that it can be used with a single operand:
int x;
Location obj;
% x;
// invalid for modulus operator
% obj; // invalid for overloaded operator
9. You cannot overload the following operators:
sizeof–>The sizeof operator
.  –>Membership operator
.*  –>Pointer-to-member operator
::  –>Scope resolution operator
?:  –>Conditional operator
typeid –> An RTTI operator
const_cast –> A type cast operator
dynamic_cast  –>A type cast operator
reinterpret_cast –> A type cast operator
static_cast –>A type cast operator
10. Most of the operators can be overloaded by using either member or nonmember functions. However,
you can use only member functions to overload the following operators:
= –> Assignment operator
( ) –>Function call operator
[] –>Subscripting operator
->  –>Class member access by pointer operator
Operator Overloading Using Friend Function
You can overload an operator for a class by using a nonmember function, which is usually a friend of the class.
Since a friend function is not a member of the class, it does not have a this pointer. Therefore, an overloaded
friend operator function is passed the operands explicitly. This means that a friend function that overloads a
binary operator has two parameters, and a friend function that overloads a unary operator has one parameter.
In this program, the operator+ ( ) function is made into a friend:
class Location
{
int longitude, latitude;
public:
Location() {} // needed to construct temporaries
Location(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << ” “;
cout << latitude << “\n”;
}
friend Location operator+(Location op1, Location op2); // now a friend
};
// Now, + is overloaded using friend function.
Location operator+(Location op1, Location op2)
{
Location temp;
temp.longitude = op1.longitude + op2.longitude;
temp.latitude = op1.latitude + op2.latitude;
return temp;
}
int main()
{
Location ob1(10, 20), ob2( 5, 30);
ob1 = ob1 + ob2;
ob1.show();
return 0;
}
Using a Friend to Overload ++ or – – :
If you want to use a friend function to overload the increment or decrement operators, you must pass the
operand as a reference parameter. This is because friend functions do not pass this pointer, rather they pass a
copy of the operand. Thus, no changes made to that parameter affect the operand that generated the call.
However, you can remedy this situation by specifying the parameter to the friend operator function as a
reference parameter. This causes any changes made to the parameter inside the function to affect the operand
that generated the call.
class Location
{
int longitude, latitude;
public:
Location() {}
Location(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << ” “;
cout << latitude << “\n”;
}
Location operator=(Location op2);
friend Location operator++(Location &op);
friend Location operator–(Location &op);
};
// Overload assignment for Location.
Location Location::operator=(Location op2)
{
longitude = op2.longitude;
latitude = op2.latitude;
return *this; // i.e., return object that generated call
}
// Now a friend; use a reference parameter.
Location operator++(Location &op)
{
op.longitude++;
op.latitude++;
return op;
}
// Make op– a friend; use reference.
Location operator–(Location &op)
{
op.longitude–;
op.latitude–;
return op;
}
int main()
{
Location ob1(10, 20), ob2;
ob1.show();
++ob1;
ob1.show(); // displays 11 21
ob2 = ++ob1;
ob2.show(); // displays 12 22
–ob2;
ob2.show(); // displays 11 21
return 0;
}
If you want to overload the postfix versions of the increment and decrement operators using a friend, simply
specify a second, dummy integer parameter. For example, this shows the prototype for the friend, postfix
version of the increment operator relative
to Location.
friend Location operator++ (Location &op, int x);
Friend Operator Functions Add Flexibility
In many cases, whether you overload an operator by using a friend or a member function makes no functional
difference. In those cases, it is usually best to overload by using member functions. However, there is one
situation in which overloading by using a friend increases the flexibility of an overloaded operator. Let’s
examine this case now.
As you know, when you overload a binary operator by using a member function, the object on the left side of
the operator generates the call to the operator function. Further, a pointer to that object is passed in the this
pointer. Now, assume some class called CL that defines a member operator+ ( ) function that adds an object of
the class to an integer. Given an object of that class called Ob, the following expression is valid:
Ob + 100 // valid
In this case, Ob generates the call to the overloaded + function, and the addition is performed. But what happens
if the expression is written like this?
100 + Ob // invalid
In this case, it is the integer that appears on the left. Since an integer is a built-in type, no operation between an
integer and an object of Ob’s type is defined. Therefore, the compiler will not compile this expression.
friend Location operator+(Location op1, int op2);
friend Location operator+(int op1, Location op2);
// + is overloaded for Location + int.
Location operator+(Location op1, int op2)
{
Location temp;
temp.longitude = op1.longitude + op2;
temp.latitude = op1.latitude + op2;
return temp;
}
// + is overloaded for int + Location.
Location operator+(int op1, Location op2)
{
Location temp;
temp.longitude = op1 + op2.longitude;
temp.latitude = op1 + op2.latitude;
return temp;
}
Home
Copyright © TechCSE Urang-kurai