CRC - Block2 Unit 2
CRC - Block2 Unit 2
Introduction
Objectives
Function Overloading
2.2.1 How Function Overloading is Achieved
2.2.2 How Function Calls are Matched with Overload Functions
Function Overloading and Ambiguity
2.3
Ambiguous Matches
Multiple Arguments
Operator Overloading
2.5.1 Why to overload operators
2.5.2 Member vs. non-member operators
2.5.3 General rules for operator overloading
2.5.4 Why some operators cant be overload
Defining operator overloading
2.6.1 Syntax
Summary
Answers to Check Your Progress
Further Readings
2.3
2.4
2.5
2.6
2.7
2.8
2.9
Page Nos.
35
35
36
42
43
45
48
70
70
73
2.0 INTRODUCTION
When you create an object (a variable), you give a name to a region of storage.
A function is a name for an action. By making up names to describe the system at
hand, you create a program that is easier for people to understand and change.
Function overloading is one of the defining aspects of the C++ programming
language. Not only does it provide support for compile time polymorphism, it also
adds flexibility and convenience. In addition, function overloading means that if you
have two libraries that contain functions of the same name, they wont conflict as long
as the argument lists are different. Well look at all these factors in detail across this
unit.
In C++, you can overload most operators so that they perform special operations
relative to classes that you create. When an operator is overloaded, none of its original
meanings are lost. Operator overloading allows the full integration of new class type
into programming environment. After overloading the appropriate operators, you can
use objects in expressions in just the same way that you use C++s built-in data types.
Operator overloading also forms the basis of C++s approach to I/O. Function
overloading and operator overloading really arent very complicated. By the time you
reach the end of this unit, you shall learn when to use them and also underlying
mechanisms that implement them during compiling and linking.
2.1 OBJECTIVES
After going through this unit, you will be able to:
Inheritance and
Polymorphism in C + +
Overloading of
functions with
different return
types are not
allowed.
Function overloading refers to using the same thing for different purposes. C++
permits the use of different functions with the same name. However such functions
essentially have different argument list. The difference can be in terms of number or
type of arguments or both. These functions can perform a variety of different tasks.
This process of using two or more functions with the same name but differing in the
signature is called function overloading. It is only through these differences that the
compiler knows which function to call in any given situations.
Consider the following function:
int add (int a, int b)
{
return a + b;
}
This trivial function adds two integers. However, what if we also need to add two
floating point numbers? This function is not at all suitable, as any floating point
parameters would be converted to integers, causing the floating point arguments to
lose their fractional values.
One way to work around this issue is to define multiple functions with slightly
different names:
int add (int a, int b)
{
return a + b;
}
double addition (double p, double q)
{
return p + q;
}
However, for best effect, this requires that you define a consistent naming standard,
remember the name of all the different flavors of the function, and call the correct one
(calling add() for addition of double type numbers with integer parameters may
produce the wrong result due to precision issues).
Function overloading provides a better solution. Using function overloading, we can
declare another add () function that takes double parameters:
double add (double p, double q)
We now have two version of add ():
36
Operator Overloading
{
return p + q;
}
//prototype 1
//prototype 2
//prototype 3
//uses prototype 1
//uses prototype 2
//uses prototype 3
37
Inheritance and
Polymorphism in C + +
38
Output
Operator Overloading
absoulte value of -5 = 5
The use of overloading may not have reduced the code complexity /size but has
definitely made it easier to understand and avoided the necessity of remembering
different names for each version function which perform identically the same task.
//func(int i) is called
//func(double i) is called
39
Inheritance and
Polymorphism in C + +
Operator Overloading
For example:
void Print(float fValue);
void Print(struct sValue);
Print('a'); // promoted to match Print(float)
In this case, because there is no Print(char), and no Print(int), the a is converted to a
float and matched with Print(float).
Note that all standard conversions are considered equal. No standard conversion is
considered better than any of the others.
4) Finally, C++ tries to find a match through user-defined conversion. Although we
have not covered classes yet, classes (which are similar to structs) can define
conversions to other types that can be implicitly applied to objects of that class.
For example, we might define a class X and a user-defined conversion to int.
class X; // with user-defined conversion to int
void Print(float fValue);
void Print(int nValue);
X cValue; // declare a variable named cValue of type class X
Print(cValue); // cValue will be converted to an int and matched to Print(int)
Although cValue is of type class X, because this particular class has a user-defined
conversion to int, the function call Print(cValue) will resolve to the Print(int) version
of the function.
Inheritance and
Polymorphism in C + +
In the case of Print('p'), C++ can not find an exact match. It tries promoting a to an
int, but there is no Print (int) either. Using a standard conversion, it can convert a to
both an unsigned int and a floating point value. Because all standard conversions are
considered equal, this is an ambiguous match.
Print(10) is similar. 10 is an int, and there is no Print(int). It matches both calls via
standard conversion.
Print(1.14) might be a little surprising, as most programmers would assume it matches
Print(float). But remember that all literal floating point values are doubles unless they
have the f suffix. 1.14 is a double, and there is no Print (double). Consequently, it
matches both calls via standard conversion.
Ambiguous matches are considered a compile-time error. Consequently, an
ambiguous match needs to be disambiguated before your program will compile. There
are two ways to resolve ambiguous matches:
1) Often, the best way is simply to define a new overloaded function that takes
parameters of exactly the type you are trying to call the function with. Then C++
will be able to find an exact match for the function call.
2) Alternatively, explicitly cast the ambiguous parameter(s) to the type of the
function you want to call. For example, to have Print(10) call the Print(unsigned
int),
2.4
MULTIPLE ARGUMENTS
If there are multiple arguments, C++ applies the matching rules to each argument in
turn. The function chosen is the one for which each argument matches at least as well
as all the other functions, with at least one argument matching better than all the other
functions. In other words, the function chosen must provide a better match than all the
other candidate functions for at least one parameter, and no worse for all of the other
parameters.
In the case that such a function is found, it is clearly and unambiguously the best
choice. If no such function can be found, the call will be considered ambiguous.
42
Operator Overloading
ii)
::
c) ( )
d) ~
iii)
iv)
->
b) &
c) *
d) >>
Inheritance and
Polymorphism in C + +
The word
polymorphis
m is derived
from the
Greek words
poly and
morphism.
This session deals with overloading of operators to make Abstract Data Types
(ADTS) more natural, and closer to fundamental data types.
44
Operator Overloading
(ii)
You cannot redefine the meaning of operators when applied to built-in data
types.
(ii)
(iii)
(iv)
(v)
(vi)
If an operator can be used as either a unary or a binary operator (&, *, +, and ), you can overload each use separately.
(viii)
(ix)
(x)
(xi)
Overloading + doesn't overload +=, and similarly for the other extended
assignment operators.
(xii)
(xiii)
(xiv)
++ and -- need special treatment because they are prefix and postfix operators.
(xv)
There are special issues with overloading assignment (=). Assignment should
always be overloaded if an object dynamically allocates memory.
45
Inheritance and
Polymorphism in C + +
<
*
>
/
+=
%
-=
^
*=
&
/=
|
%=
~
^=
!
&=
|=
<<
>>
<<=
>>=
==
!=
<=
>=
&&
||
++
--
->*
->
()
[]
new
delete
new[]
delete[]
.*
::
sizeof
?:
But it does not suite for ? : (conditional operator) as it does not take name as
parameter. The reason we cannot overload ? : is that it takes 3 argument rather than 2
or 1. There is no mechanism available by which we can pass 3 parameters during
operator overloading.
Operator Overloading
2.6.1 Syntax
Defining an overloaded operator is like defining a function, but the name of that
function is operator #, in which # represents the operator thats being overloaded. The
number of arguments in the overloaded operators argument list depends on two
factors:
1. Whether its a unary operator (one argument) or a binary operator (two arguments).
2. Whether the operator is defined as a global function (one argument for unary, two
for binary) or a member function (zero arguments for unary, one for binary the
object becomes the left-hand argument).
It may look like following way:
Return_type class_name :: operator op (op_argument_list)
{
Body of function
}
Here return_type is the type of value returned by the specified operation and op is the
operator being overloaded. The op is preceded by the keyword operator. Operator op
is the name of function. They may be also friend functions. Member function has no
argument for unary operator and one argument for binary operator. This is because the
object used to invoke the member function is passed implicitly and so it available to
member function. This case is not with the friend function. Friend function will have
one argument for unary operator and two arguments for binary operator. All the
arguments may be passed either by value or by reference. Following lines define the
steps in overloading the operators
a. Build a class that defines the data type that is going to use in operation of
overloading.
b. Declare the operator function operator op() in public area of class.
c. Now define the operator function to implement the required operations.
Inheritance and
Polymorphism in C + +
48
#include<iostream.h>
#include<conio.h>
Class complex
{
int real, imaginary;
Public:
complex()
{
}
complex(int a, int b)
{
real = a;
imaginary = b;
}
void operator-();
void display()
{
cout<<Real value<<real<<endl;
cout<<imaginary value<<imaginary<<endl;
}
};
void complex::operator-()
{
real = -real;
imaginary = -imaginary;
}
void main()
{
Clrscr();
complex c1(10,12);
cout<< real and imaginary value befor operation<<endl;
c1.display();
c1;
//c1- /*It will give error*/
cout<< real and imaginary value after operation<<endl;
c1.display();
getch();
}
Output
Operator Overloading
49
Inheritance and
Polymorphism in C + +
Output:
Real and imaginary value before operation
real value is 50
Output
Real sum is 30
Imaginary sum is 50
50
Explanation: Output is easily predictable, and most of the program is same as above
program. Difference lies in void complex :: operator +(complex c) if we compare this
statement with our conventional outline statement
Operator Overloading
51
Inheritance and
Polymorphism in C + +
Output:
real value is : 40
imaginary value is : 70
52
Operator Overloading
void main(void)
{
Inc a, b(10), c, d, e(5), f(10);
cout << "Before using the operator ++()\n";
cout << "a = ";
a.display();
cout << "b = ";
b.display();
++a;
b++;
cout << "After using the operator ++()\n";
cout << "a = ";
a.display();
cout << "b = ";
b.display();
c = ++a;
d = b++;
cout << "Result prefix (on a) and postfix (on b)\n";
cout << "c = ";
c.display();
cout << "d = ";
d.display();
cout << "Before using the operator --()\n";
cout << "e = ";
e.display();
cout << "f = ";
f.display();
--e;
f--;
cout << "After using the operator --()\n";
cout << "e = ";
e.display();
cout << "f = ";
f.display();
}
Output:
Before using the operator ++()
a=0
b = 10
After using the operator ++()
a=1
b = 11
Result prefix (on a) and postfix (on b)
c=2
53
Inheritance and
Polymorphism in C + +
d = 12
Before using the operator --()
e=5
f = 10
After using the operator - -()
e=4
f=9
Note :
When specifying an overloaded operator for the postfix form of the increment or
decrement operator, the additional argument must be of type int; specifying any other
type generates an error.
Operator Overloading
cout << "c2= " << c2.getReal() << "+" << c2.getImag() << "i" << endl;
c2 = c1;
cout << "assign c1 to c2:" << endl;
cout << "c2= " << c2.getReal() << "+" << c2.getImag() << "i" << endl;
}
Output:
c1= 5+10i
c2= 50+100i
assign c1 to c2:
c2= 5+10i
Inheritance and
Polymorphism in C + +
Output:
c1 = 5+10i
Using overloaded <<
c1 = 5+10i
Note that we just used:
56
Operator Overloading
57
Inheritance and
Polymorphism in C + +
Output:
Operator
Overloading
Operator Overloading
58
Operator Overloading
Example
Class Complex
{
Public:
Friend istream & operator >>(istream &is, Complex &c2);
Friend ostream & operator <<(ostream &os, Complex &c2);
Private:
Int real,imaginary;
};
Istream& operator >>(istream &is, Complex &c2);
{
Cout<<enter real and imaginary<<endl;
Is>>c2.real>>c2.imaginary;
Return(is);
}
Istream& operator <<(ostream &os, Complex &c2)
{
Os<<the complex number is <<endl;
Os<<c2.real<<I<<c2.imaginary;
Return(os);
}
Void main()
{
Complex c1,c2;
Cin>>c1;
Cout<<c1;
Cin>>c2;
Cout<<c2;
}
This operator function have to be declared friends since they have to access the user
class and the objects of stream and ostream classes that are sytem defined. Since these
operators functions are friend functions, the two objects cin and cout are passed as
arguments, along with the objects of the user class. They return the isteam and
ostream objects so that the operator can be chained. That is the above two input
statements can also be written as,
Cin>>c1>>c2;
Cout<<c1<<c2;
59
Inheritance and
Polymorphism in C + +
ii)
iii)
iv)
60
three arguments
2.7
SUMMARY
Operator Overloading
In this unit, we have discussed two important concepts about overloading namely
function overloading and operator overloading. As a part of function overloading, you
learnt that you can create multiple functions of the same name that work differently
depending on parameter type. Function overloading can lower a programs complexity
significantly while introducing very little additional risk. Although this particular
lesson is long and may seem somewhat complex (particularly the matching rules), in
reality function overloading typically works transparently and without any issues. The
compiler will flag all ambiguous cases, and they can generally be easily resolved.
Operator overloading is common-place among many efficient C++ programmers.
Operating overloading allows you to pass different variable types to the same function
and produce different results. Operator overloading permits user-defined operator
implementations to be specified for operations where one or both of the operands are
of a user-defined class or struct type. Operator overloading allows the programmer to
define how operators should interact with various data types. It is so because operators
in C++ are implemented as functions, operator overloading works very analogously to
function overloading. Operator overloading is the ability to tell the compiler how to
perform a certain operation when its corresponding operator is used on one or more
variables.
2)
First, C++ tries to find an exact match. This is the case where the actual
argument exactly matches the parameter type of one of the overloaded
functions. For example:
Inheritance and
Polymorphism in C + +
4)
2)
62
You cannot redefine the meaning of operators when applied to built-in data
types.
Operator Overloading
3)
Function overloading is like you have different functions with the same name
but different signatures working differently. So, the compiler can differentiate
and find out which function to call depending on the context. In case of
operator overloading, you try to create your own functions which are called
when the corresponding operator is invoked for the operands.
One important thing to understand is that you can create as many functions as
you want with the same name and different signatures so that they can work
differently but for a particular class, you cannot overload the operator
function based on number of arguments. There is a fundamental reason
behind this.
According to the rules, you can not create your own operators and you have to
use already available operators. Another thing is, since the operators are
already defined for use with built-in types, you cant change their
characteristics. For example, the binary operator '+' always takes two
parameters, so for this you cannot create a function that takes three
parameters. But you can always overload them based on the type of the
parameters.
4)
63
Inheritance and
Polymorphism in C + +
64
1)
2)
3)
4)
5)
www.learncpp.com/cpp-tutorial
6)
http://www.bogotobogo.com/cplusplus