Operator Overloading- Intro


The following topics are covered in this section:


An Introduction to Operator Overloading

Operator overloading means giving additional meaning to normal operators when they are applied to user defined data types. How will the compiler recognize this? The compiler identifies that it is an overloaded operator by looking at the data type of the operand (i.e. if it is a user defined data type then the compiler knows it is an overloaded operator; if it is a built-in data type then the compiler will do the normal operation).

You have to remember that objects are defined by you (or the programmer). You choose the data that comes under an object. The data type that you use will be in-built data types like integer or character but the object as a whole is user defined. Hence it is not possible to add two objects (even though they belong to the same class) using the + sign. The addition operator is designed to work only on in-built data types like integers, float etc. It cannot add two objects. But using operator overloading you could use the same + sign to add two objects. Operator overloading is a form of polymorphism (for example, the + operator once overloaded in a class can be used in different ways depending on the operands. If the operands are objects then the overloaded + is used. If the operands are fundamental data types then the normal + operation is carried out).

Syntax:

return-data-type operator symbol-of-operator (parameters)
{
//body of the function
}

Example:

void operator ++ ( )
{
body of function;
}

The word ‘operator’ is a keyword and is necessary for overloading an operator. Let us write a program to overload a unary operator (++)

class timer
{

private :
    int countdown;
public :
timer ( ) : countdown (100)                 // Constructor
{ }
int display ( )
{
        return countdown;
}
void operator -- ( )                         // -- is overloaded operator.
{
        -- countdown;
}
};
int main ( )
{ timer c1, c2;
cout<<"\nInitial c1 value : "<<c1.display( );
cout<<"\nInitial c2 value : "<<c2.display( );
--c1; // -- is an overloaded operator
--c2; // Compiler knows this because c1 and c2 are user defined data
--c2;
--c2;
cout<<"\n\nFinal c1 value : "<<c1.display( );
cout<<"\nFinal c2 value : "<<c2.display( );
return 0;
}

The output would be:

Initial c1 value : 100
Initial c2 value : 100
Final c1 value : 99
Final c2 value : 97

When compiler comes across --c1 it does the following. It knows that c1 is an object which is a user defined data type.
But -- can operate only on in-built data types. Now it thinks over and remembers that -- was already overloaded using the operator function within the class timer. So it goes back to the operator function and reads through what is written in the body. No return data type and no arguments. This makes its work a lot easier. It just has to perform one instruction.

--countdown;
countdown is an integer data type. The compiler decreases the value of countdown by one and goes back to the original program. All this was done when it encountered the line --c1. Hence the count of c1 only is decreased by one when the compiler reads the line

--c1
Similarly, when the compiler comes to --c2 it decreases the count of c2 by one.


Operator Overloading with return data type

Consider the same example as in the previous section. This time we shall make use of the return data type in the operator function to return something to the main ( ) function.

class timer
{

private :
int countdown;
public :
timer ( ) : countdown (100)
{ }
timer (int t) : countdown (t)                 // Constructor with arguments
{ }
int display ( )
{
        return countdown;
}
timer operator -- ( )
{
        -- countdown;
        return timer(countdown);                //unnamed object created using 2nd constructor
}
};
int main ( )
{ timer c1, c2;
cout<<"\nInitial c1 value : "<<c1.display( );
cout<<"\nInitial c2 value : "<<c2.display( );
c2=--c1;
cout<<"\n\nFinal c1 value : "<<c1.display( );
cout<<"\nFinal c2 value : "<<c2.display( );
return 0;
}

The output is:

Initial c1 value : 100
Initial c2 value : 100
Final c1 value : 99
Final c2 value : 99

In the above program we overload the same unary operator but use a return data type timer. Timer is the name of the class itself. It would seem as if the function is returning a class. But a class is just a template and means nothing without objects. Hence the function is actually returning an object belonging to class ‘timer’.

--countdown;
return timer(countdown);

As in the earlier program, the overloaded operator just decreases the ‘countdown’ value by one. It does the same here. We know that ‘timer’ is the name of the class. Within the braces we have written countdown. In the program countdown of c1 was 100 and then it became 99 because of the

--countdown;

statement. Now countdown is 99. Hence the return statement is equal to timer (99). This line creates an object without a name (an unnamed object). The constructor with parameters is made use of to initialize this object. The ‘countdown’ value of the unnamed object is initialized to 99. Now all this is supposed to be returned to the calling function.

c2 = --c1;
c2 is an object and hence the value of count of the unnamed object is stored in c2. So c2's count becomes 99.

What do you think will happen if we type:

c2 = c1--;

instead of:

c2 = --c1;

We have overloaded for the prefix -- operator and not the postfix -- operator. If you want to overload the postfix operator what should we do? The compiler should be able to distinguish between the two forms and hence according to C++ norms, you should use an integer argument if you want to overload the postfix form of an unary operator. In this case you should modify the function header as:

timer operator -- (int x)

The integer ‘x’ is just for telling the compiler that this function corresponds to the postfix operator. The same method is used for the unary increment operator ++ also.

In case you don’t overload the postfix operator (but have overloaded the prefix operator), and you use the postfix operator, then your compiler might display a warning message and make use of the prefix overloaded form.


Go back to the Contents Page 2


Copyright © 2004 Sethu Subramanian All rights reserved.