Thursday, October 21, 2010

Operator Overloading in c++

In C++ the overloading principle applies not only to functions, but to operators too. That is, the meaning of operators can be extended from built-in types to user-defined types. In this way a programmer can provide his or her own operator to a class by overloading the built-in operator to perform some specific computation when the operator is used with objects of that class.

One question may arise here: is this really useful in real world implementations? Some programmers consider that overloading is not useful most of the time. This and the fact that overloading makes the language more complicated is the main reason why operator overloading is banned in Java.

Even if overloading adds complexity to the language it can provide a lot of syntactic sugar, and code written by a programmer using operator overloading can be easy, but sometimes misleading, to read. We can use operator overloading easily without knowing all the implementation's complexities. A short example will make things clear:
Complex a(1.2,1.3);     //this class is used to represent complex numbers
Complex b(2.1,3); //notice the construction taking 2 parameters for the real and imaginary part
Complex c = a+b; //for this to work the addition operator must be overloaded
The addition without having overloaded operator + could look like this:
Complex c(a);
This piece of code is not as suggestive as the first one and the readability becomes poor. Using operator overloading is a design decision, so when we deal with concepts where some operator seems fit and its use intuitive, it will make the code more clear than using a function to do the task. However, there are many cases when programmers abuse this technique, when the concept represented by the class is not related to the operator (like using + and - to add and remove elements from a data structure). In this cases operator overloading is a bad idea, creating confusion.

In order to be able to write the above code we must have the "+" operator overloaded to make the proper addition between the real members and the imaginary ones and also the assignment operator. The overloading syntax is quite simple, similar to function overloading, the keyword operator followed by the operator we want to overload as you can see in the next code sample:
class Complex
Complex(double re,double im)
Complex operator+(Complex);
Complex operator=(Complex);
double real;
double imag;
Complex Complex::operator+(Complex num)
real = real + num.GetRealPart();
imag = imag + num.GetImagPart();
return *this;
The assignment operator can be overloaded similarly. Notice that we had to call the accessor function in order to get the real and imaginary parts from the parameter since they are private. In order to bypass this difficulty we could have made the operator + a friend.

friend Complex operator+(Complex); 
We could have defined the addition operator globally and called a member to do the actual work:
Complex operator+(Complex  &num1,Complex &num2)
Complex temp(num1); //note the use of a copy constructor here
return temp;

The motivation for doing so can be understood by examining the difference between the two choices: when the operator is a member the first object in the expression must be of that particular type, when it's a global function, the implicit or user-defined conversion can allow the operator to act even if the first operand is not exactly of the same type:
Complex c = 2+b;        //if the integer 2  can be converted by the Complex class, this expression is valid
The number of operands can't be overridden, that is, a binary operator takes two operands, a unary only one. The same restriction acts for the precedence too, for example the multiplication takes place before addition. There are some operators that need the first operand to be left value: operator=, operator(), operator[] and operator->, so their use is restricted just as member functions(non-static), they can't be overloaded globally. The operator=, operator& and operator, (sequencing) have already defined meanings by default for all objects, but their meanings can be changed by overloading or erased by making them private.

Another intuitive meaning of the "+" operator from the STL string class which is overloaded to do concatenation:
string prefix("de");
string word("composed");
string composed = prefix+word;
Using "+" to concatenate is also allowed in Java, but note that this is not extensible to other classes, and it's not a user defined behavior. Almost all operators can be overloaded in C++:
+       -       *       /       %       ^       &       |
~ ! , = < > <= >=
++ -- << >> == != && ||
+= -= /= %= ^= & = |= *=
<<= >>= [ ] ( ) -> ->* new delete

The operators which cannot be overloaded -scope resolution (::), member selection (.), and member selection through a pointer to a function(.*), preprocessor convert to string(#),  preprocessor concatenate (##)...See more here.

No comments:

Post a Comment