Sunteți pe pagina 1din 11

Chapter Four: Operator Overloading

4.1 Objectives
 To understand the fundamentals of operator overloading
 To understand the differences between overloading as member function and non-member friend
function

4.2 Operator Function


In C++ an operator is just one form of function with a special naming convention. As such, it can
have return value as well as arguments or parameters. Recall the general format of function
definition:

return_value some_function( argument_type arg1, …)

An operator function definition can be done similarly, with the exception that function name must
take the form of operatorX, where X is the symbol for an operator, e.g. +,-, /, etc. For instance, to
declare multiplication operator the function prototype would look like

return_value operator*( arg_type arg1, arg_type arg2)

Therefore, function overloading principle also applies to operators. Operator overloading can be
implemented by having different type of argument(s).

4.3 Why do we need operator overloading?


Why do we need operator overloading? Do we really need it? For instance, compare the following
syntaxes to perform addition of two objects a and b of a user defined class Fraction:

a.add(b);
a+b;

which one is easier to use?


If your answer is the first statement then, our discussion ends right here. But, we assume that you are
obliged to choose the second one. Only then we can continue our discussion.
Operator overloading is needed to make operation with user defined data type, i.e., classes, can be
performed concisely.
Try the following example, to have a better feeling how addition operation does not work for a user
defined class.

Fig. 4.1 Class Fraction without operator overloading

Try to compile and see what happen?


If you fail now, it is fine. You will know how to make it works by the end of this tutorial session.
Hopefully!!!
Let’s move onto reviewing function overloading. Function overloading means having more than one
function with exactly the same function name and each function has different parameters. For
instance,

int square ( int );


double square ( double);
are example of function overloading. We have two functions with the same name square and
different type of argument, i.e., int and double. Try the following simple example.

Fig. 4.2 Function overloading

Could you compile it? What did you observe from the execution window? Why did the program
compile just fine? It is because of the signatures for both functions are different and therefore
distinguishable. Thanks to function overloading.
Most of us have been using the operators such as +, -, *, & etc. and pay little attention about what
actually is happening. We can easily add an integer with another integer( int + int ), or add a double
with a float ( double + float ) using the very same operator symbol + without questioning anything.
How do they work?
Note: Do you realize that all overloadable operators are overloaded already? Can you give
examples?

4.4 Limitation on operator overloading


Although C++ allows us to overload operators, it also imposes restrictions to ensure that operator
overloading serves its purpose to enhance and programming language itself, without compromising
the existing entity. The followings are the restrictions.
- Can not change the original behavior of the operator with built in data types.
- Can not create new operator
- Operators =, [], () and -> can only be defined as members of a class and not as global
functions
- The arity or number of operands for an operator may not be changed. For example, addition, +,
may not be defined to take other than two arguments regardless of data type.
- The precedence of the operator is preserved, i.e., does not change, with overloading
- Operators that can be overloaded

+ - * / % ^ & | ~
!
= < > += -= *= /= %= ^=
|=
<< >> >>= <<= == != <= >= &&
||
++ -- ->* , -> [] () new delete
new[] delete[]

- Operators that can not be overloaded

. .* :: :? sizeof

Warning: not to abuse operator overloading such that blurs the way how a particular operator
operates normally.
The (=) assignment operator and the (&) address operator are not needed to be overloaded since both
can work automatically with whatever data types. (=) assignment operator creates a bit-by-bit copy
of an object while the (&) address operator returns a memory address of the object. The exception
comes when we deal with classes containing pointers as members. In this case, the assignment
operator needs to be overloaded explicitly.

4.5 Choice on overloading an operator


We can implement operator overloading in three different ways, namely:
1. as member function
2. as non member friend function
3. as non member non friend function
Again, the difference is only in the implementation and do not affect at all the usage.
Whatever implementation we chose, the usage will be the same. In this section we will discuss the
first two choices, and leave the third one as exercise.
Recall our question on how operator overloading works for built-in data types. How does
it work? How several operator functions having exactly the same name do not conflict each other.
Yes, the answer is because the C++ library has overloaded the addition operator (operator+) function
for relevant data types. When the same operator is called or invoked with different types of operand,
the appropriate version of the operator is called.
Now, let’s get back on track. How can we make our program in Fig. 4.1 works? You know
the answer already. Overload operator+ function for class Fraction. Can you do it now?
Maybe not yet. You have to settle one more issue about the return type of the operator+
and the arguments. This is common issue for whatever function that we create. Considering the
previous example we know that for operator+ for class Fraction we have two operands, a and b
which are of type Fraction.

a+b;

These two arguments shall appear as the arguments of the operator+ function. However,
since here we choose to implement it as a member function. Recall about how the this pointer
works! When we have such a statement in our program, it will be interpreted by the compiler as the
left operand, a calls its member function operator+ with b as the argument.

a.operator+(b);

Next, the return value type will naturally be a Fraction object as well (You have choice
whether to return a Fraction object or a reference to Fraction object, though). So, now we have
sufficient knowledge on how to declare the prototype function. It will look like

Fraction& operator+ (const Fraction &); //return a reference


OR
Fraction operator+ (const Fraction &); // return a value
Now, lets see how we can implement it.

Fig. 4.3 Overloading operator+ as member function

Fig. 4.4 How to use the overloaded operator+


If we choose to implement it as non-member friend function, the function prototype will
look like
friend Fraction& operator+( const Fraction&, const Fraction&
);
Can you figure out the difference? Yes, now we have the two operands appear as arguments. For
there is no implicit this pointer for non-member friend function. The operation inside the function
will require some slight changes accordingly. Would you try it out?
Fig. 4.5 Overloading operator+ as non-member friend function

The usage of the overloaded function, whether implemented as member function or non-
member (friend) function does not have any difference. Exactly, the same as given in Fig. 4.4.
Note, however, that the compiler interprets the same statement slightly differently. When it sees
statement
a+b;
it is interpreted as
operator+( a, b );
Then, your curious mind may question: what is the motivation for choosing member
function over non-member (friend) function or vice versa if that’s the only difference. We would
agree with you. Before we proceed, please modify example in Fig. 4.4, the statement
c = a + b;
with
c = b + a;
What is your observation?
The same result, c=a+b = b+a. It is because the two operands a and b are of the same
type. Now let’s consider adding class Fraction object a and an integer variable b. We have two
objects of different types. Here we assume that the result, c is of type Fraction.
c = a + b;
c = b + a;
Will we be able to implement operator+ as either member function or non-member (friend)
function. Let’s implement it as member function first.

Fig. 4.6 Overloading operator+ with operands of different data types as member function

Fig. 4.7(a) invoking operator+ with operands of different data types


Fig. 4.7(b) invoking operator+ with operands of different data types

What do you observe from Fig. 4.7(a) and (b)? The overloaded operator+ does work for
a+b but does NOT work for b+a. Do you know why?
Next, we will overload operator+ as non-member friend function.
Fig. 4.8 Overloading operator+ with operands of different data types as non-member function

Fig. 4.9(a) invoking operator+ with operands of different data types


Fig. 4.9(b) invoking operator+ with operands of different data types
This time what do you observe?
This time our result is exactly the opposite of the previous one.
The conclusion is that if we expect to use both notation, i.e., a+b and b+a, we have to overload
operator+ twice as member function and non-member friend function. DO YOU KNOW YHW?

S-ar putea să vă placă și