Headlines News :
Home » , , » Learn C++ in 12 Days - Day 10

Learn C++ in 12 Days - Day 10

Written By Ente Malayalam on Friday, May 24, 2013 | 5/24/2013

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. 

Share this article :

0 comments:

Post a Comment

 
Support : Creating Website | Johny Template | Maskolis | Johny Portal | Johny Magazine | Johny News | Johny Demosite
Copyright © 2011. Education World - All Rights Reserved
Template Modify by Creating Website Inspired Wordpress Hack
Proudly powered by Blogger