DAY
– 10
In yesterday’s class we
have seen overloading of binary operator using member and friend. Now we will
see a slight modification of the same program in today’s class.
For the same binary
operator + ,first let’s try to do
O1
+ 10
//complex.h
#include
<iostream>
using
namespace std;
class
Complex {
private:
double Real;
double Imaginary;
public:
Complex() : Real(0.0),
Imaginary(0.0) {}
Complex(double r, double i) :
Real(r), Imaginary(i) {}
Complex operator + (int);
double Return_Real();
double Return_Imaginary();
};
//complex_library.cpp
#include
"complex.h"
Complex
Complex :: operator + (int a) {
Complex Temp;
Temp.Real = Real + a;
Temp.Imaginary = Imaginary;
return Temp;
}
double
Complex :: Return_Real() {
return Real;
}
double
Complex :: Return_Imaginary() {
return Imaginary;
}
//complex_application.cpp
#include
"complex.h"
int
main() {
Complex O1;
Complex O2(1.1, 2.2);
O1 = O2 + 10;
cout << O1.Return_Real() <<
endl;
cout << O1.Return_Imaginary()
<< endl;
return 0;
}
If
written as global function :
//complex.h
#include
<iostream>
using
namespace std;
class
Complex {
private:
double Real;
double Imaginary;
public:
Complex() : Real(0.0),
Imaginary(0.0) {}
Complex(double r, double i) :
Real(r), Imaginary(i) {}
friend Complex operator +
(Complex&, int);
double Return_Real();
double Return_Imaginary();
};
//complex_library.cpp
#include
"complex.h"
Complex
operator + (Complex &obj, int a)
{
Complex Temp;
Temp.Real = obj.Real + a;
Temp.Imaginary = obj.Imaginary;
return Temp;
}
double
Complex :: Return_Real() {
return Real;
}
double
Complex :: Return_Imaginary() {
return Imaginary;
}
//complex_application.cpp
#include
"complex.h"
int
main() {
Complex O1;
Complex O2(1.1, 2.2);
O1 = O2 + 10;
cout << O1.Return_Real() <<
endl;
cout << O1.Return_Imaginary()
<< endl;
return 0;
}
Now lets try to do something similar
to this. Instead of doing O1 + 10, lets try to do
10
+ O1
If
you see the internal representation as member and friend :
Member
: 10.operator+(O1)
Global
: operator+ (10, O1)
You
can see that when written as member function, as per the syntax the invoking
person is going to be a constant and not an object. Since member functions of
your class can be invoked only by the objects of your class, overloading binary
operator as member function when LHS operand is a constant is not possible. The
only other possible way here is friend functions. So writing it as friend
function :
//complex.h
#include
<iostream>
using
namespace std;
class
Complex {
private:
double Real;
double Imaginary;
public:
Complex() : Real(0.0),
Imaginary(0.0) {}
Complex(double r, double i) :
Real(r), Imaginary(i) {}
friend Complex operator + (int,
Complex);
double Return_Real();
double Return_Imaginary();
};
//complex_library.cpp
#include
"complex.h"
Complex
operator + (int a, Complex obj) {
Complex Temp;
Temp.Real = obj.Real + a;
Temp.Imaginary = obj.Imaginary;
return Temp;
}
double
Complex :: Return_Real() {
return Real;
}
double
Complex :: Return_Imaginary() {
return Imaginary;
}
//complex_application.cpp
#include
"complex.h"
int
main() {
Complex O1;
Complex O2(1.1, 2.2);
O1 = 10 + O2;
cout << O1.Return_Real() <<
endl;
cout << O1.Return_Imaginary()
<< endl;
return 0;
}
Now let’s move on to
unary ++ operators. As you know there are different types of unary operators
like ++, --, -, +, ! etc. in our class we are going to concentrate on the
increment operator only. Try to relate the same thing to all other unary
operators.
As you know, increment
and decrement have two different versions. Pre and post. We will be seeing both
these things. Lets work with the same class Complex. Lets say we have two
objects, O1 and O2. So what we want to do is
O1 = ++O2;
O1 = O2++;
Lets try to get the internal representations of both
pre and post.
Pre – increment : Member : O2.operator++ ()
Pre-increment : Global : operator++ (O2)
Post-increment : Member: O2.operator++();
Post-increment : Global : operator++ (O2)
If you notice, the syntax of pre and post increment
operator functions are exactly the same. Ie) same functions names but they
doesn’t even differ in terms of argument list. Or we should say, it is
violating function overloading principles. So as a remedy for this, designers
recommend to include a dummy variable
along with the post increment versions. So accordingly lets try to overload the
++ operator for the class complex.
++
overloading as member function :
//complex.h
#include
<iostream>
using
namespace std;
class
Complex {
private:
double Real;
double Imaginary;
public:
Complex() : Real(0.0),
Imaginary(0.0) {}
Complex(double r, double i) :
Real(r), Imaginary(i) {}
Complex operator ++ ();
Complex operator ++ (int);
double Return_Real();
double Return_Imaginary();
};
//complex_library.cpp
#include
"complex.h"
Complex
:: operator ++ () {
++Real;
++Imaginary;
return *this;
}
Complex
Complex :: operator ++ (int) {
Complex Temp;
Temp.Real = Real++;
Temp.Imaginary = Imaginary++;
return Temp;
}
double
Complex :: Return_Real() {
return Real;
}
double
Complex :: Return_Imaginary() {
return Imaginary;
}
//complex_application.cpp
#include
"complex.h"
int
main() {
Complex O1;
Complex O2(1.1, 2.2);
Complex O3(3.3, 4.4);
O1 = ++O2;
cout << "O1.Real =
"<< O1.Return_Real() << endl;
cout << "O1.Imaginary = "<<
O1.Return_Imaginary() << endl;
cout << "O2.Real =
"<< O2.Return_Real() << endl;
cout << "O2.Imaginary =
"<< O2.Return_Imaginary() << endl;
O1 = O3++;
cout << "O1.Real =
"<< O1.Return_Real() << endl;
cout << "O1.Imaginary =
"<< O1.Return_Imaginary() << endl;
cout << "O3.Real =
"<< O3.Return_Real() << endl;
cout << "O3.Imaginary =
"<< O3.Return_Imaginary() << endl;
return 0;
}
++
overloading as friend function :
//complex.h
#include
<iostream>
using
namespace std;
class
Complex {
private:
double Real;
double Imaginary;
public:
Complex() : Real(0.0),
Imaginary(0.0) {}
Complex(double r, double i) :
Real(r), Imaginary(i) {}
double Return_Real();
double Return_Imaginary();
friend Complex operator++
(Complex&);
friend Complex operator++
(Complex&, int);
};
//complex_library.cpp
#include
"complex.h"
Complex
operator ++ (Complex &obj1) {
Complex Temp;
Temp.Real = ++obj1.Real;
Temp.Imaginary = ++obj1.Imaginary;
return Temp;
}
Complex
operator ++ (Complex &obj1, int)
{
Complex Temp;
Temp.Real = obj1.Real++;
Temp.Imaginary = obj1.Imaginary++;
return Temp;
}
double
Complex :: Return_Real() {
return Real;
}
double
Complex :: Return_Imaginary() {
return Imaginary;
}
//complex_application.cpp
#include
"complex.h"
int
main() {
Complex O1;
Complex O2(1.1, 2.2);
Complex O3(3.3, 4.4);
O1 = ++O2;
cout << "O1.Real = "
<< O1.Return_Real() << endl;
cout << "O1.Imaginary =
" << O1.Return_Imaginary() << endl;
cout << "O2.Real = "
<< O2.Return_Real() << endl;
cout << "O2.Imaginary =
" << O2.Return_Imaginary() << endl;
O1 = O3++;
cout << "O1.Real = "
<< O1.Return_Real() << endl;
cout << "O1.Imaginary =
" << O1.Return_Imaginary() << endl;
cout << "O3.Real = "
<< O3.Return_Real() << endl;
cout << "O3.Imaginary =
" << O3.Return_Imaginary() << endl;
return 0;
}
Note
:
If
you notice, in the above program, the arguments are taken by reference. It is a
must. Else the incrementations done in the global functions wont be reflected
back in main. another important thing, the design is made in such a manner that
the dummy argument is always made as the second argument.
Now
lets move on to input / output operators.
Lets
say for the same class complex : we want to do
cin
>> O1;
cout
<< O1;
as
usual if we try to get the internal representation as member and friend
Member
function for >> : cin.operator >> (O1)
Global
function for >> : operator >> (cin, O1)
Member
function for << : cout . operator << (O1)
Global
function for << : operator << (O1)
Just
like our 10 + O1 , we can see that writing it as member function is not going
to work since the invoking person is cin and cout which are not objects of the
class complex. Because of this reason, >> and << becomes operators
which can be overloaded only using friend functions. Lets try to write the
program for it.
//complex.h
#include
<iostream>
using
namespace std;
class
Complex {
private:
double Real;
double Imaginary;
public:
Complex() : Real(0.0),
Imaginary(0.0) {}
friend void operator <<
(ostream &, Complex);
friend void operator >>
(istream &, Complex &);
};
//complex_library.cpp
#include
"complex.h"
void
operator << (ostream &obj1, Complex obj2) {
obj1 << obj2.Real <<endl;
obj1 << obj2.Imaginary <<
endl;
}
void
operator >> (istream &obj1, Complex &obj2) {
obj1 >> obj2.Real;
obj1 >> obj2.Imaginary;
}
//complex_application.cpp
#include
"complex.h"
int
main() {
Complex o1;
cin >> o1;
cout << o1;
}
Note
:
From
the above program we can understand that, cin is an object of class istream and
cout is an object of class ostream. If
you notice you can see that the objects of istream and ostream are taken by
reference. This is because, the copy constructor needed for pass by value in
istream and ostream classes are defined in the protected section of the class.
While
overloading extraction, the object of class Complex is also taken by reference
to ensure that the values inputted in the function is reflected back in the
main.
Let
me modify the application layer of the above program as shown below :
//complex_application.cpp
#include
"complex.h"
int
main() {
Complex o1, o2;
cin >> o1 >> o2;
cout << o1 << endl;
cout << o2 << endl;
}
If
you notice you can see that after doing
cin >> o1 or cout << o1, cin and cout should return back to
do cin >> o2 and cout << endl. But in our program, we have
mentioned the return type as void. So modifying the header and library for the
above program :
//complex.h
#include
<iostream>
using
namespace std;
class
Complex {
private:
double Real;
double Imaginary;
public:
Complex() : Real(0.0),
Imaginary(0.0) {}
friend ostream& operator
<< (ostream &, Complex);
friend istream& operator
>> (istream &, Complex &);
};
//complex_library.cpp
#include
"complex.h"
ostream&
operator << (ostream &obj1, Complex obj2) {
obj1 << obj2.Real <<endl;
obj1 << obj2.Imaginary <<
endl;
return obj1;
}
istream&
operator >> (istream &obj1, Complex &obj2) {
obj1 >> obj2.Real;
obj1 >> obj2.Imaginary;
return obj1;
}
Jus
like the previous program, to avoid return by value which demands copy
constructor, cin and cout are returned by reference from the function.
We
have seen two operators which can be overloaded as only friend functions. There
is a set of four operators which can be overloaded only as members functions.
They are
1.
= : assignment
operator
2.
-> : pointer
to member
3.
[
] : subscript operator
4.
(
) : function brackets
Let
see the reason for this. Let me explain this with respect to assignment
operator. Please try to relate it to all other three operators.
0 comments:
Post a Comment