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

Learn C++ in 12 Days - Day 9

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

DAY – 8
DAY – 9
             
Friends:
            Till yesterday’s class I was telling you that the private data members of a class can be accessed only with in the class and that too using the member functions of the class. Now the speciality of the concept friends which we are going to study now is, it can grant permission to a non member function of the class to access the private property of the class. Non-member functions can be of two types. It can be either a global function or a member function of another class. In today’s class we will simply concentrate on how a global function can be given permission to access the private data of one or more than one class of yours.
            The basic concept of friends is very simple. If an external function have to access the private members of the class, the class have to simply tell the compiler that the external function is a friend of the class. And this is done by declaring the prototype declaration of the function inside the class preceded with the keyword friend. Just see the below example where a global function is made as a friend of a single class.
//Car.h
#include <iostream>
using namespace std;
class Car       {
        private:
                char Make[20];
                char Model_Name[20];
                const int Seating_Capacity;
                const int Fuel_Capacity;
                float Price;
                static float Discount;
        public:
                Car() : Seating_Capacity(4), Fuel_Capacity(35)  {
                        strcpy(Make, "Hyundai");
                        strcpy(Model_Name, "Santro");
                        Price = 400000.00;
                }
                Car(char *m, char *n, int s, int f, float p) : Seating_Capacity(s), Fuel_Capacity(f)    {
                        strcpy(Make, m);
                        strcpy(Model_Name, n);
                        Price = p;
                }
                static void Set_Discount(float);
                static float Return_Discount();
                const char* Return_Model_Name() const;
                const char* Return_Make() const;
                float  Return_Price() const;
                friend void Festival_Offer(Car &);
};
//car_library.cpp
#include "car.h"

float Car :: Discount = 0.05;

void Car :: Set_Discount(float D)       {
        Discount = D;
}

float Car :: Return_Discount()  {
        return Discount;
}

const char* Car :: Return_Make() const  {
        return Make;
}

const char* Car :: Return_Model_Name() const    {
        return Model_Name;
}

float Car :: Return_Price() const       {
                return Price;
}

void Festival_Offer(Car &Sample)        {
        Car :: Set_Discount(0.10);
        Sample.Price = Sample.Price - (Sample.Price * Sample.Discount);
}

//car_application.cpp

#include "car.h"

int main()      {
        Car Hyundai("hyundai", "santro",4, 35, 40000);

        cout << Hyundai.Return_Price() << endl;

        Festival_Offer(Hyundai);
        cout << Hyundai.Return_Price() << endl;

        return 0;
}

It is even possible to make a global function as a friend of two classes. Only thing we have to do is, the function should be made as a friend of both the classes. Only problem which can arise here is, if ever the name of the second class appears in the prototype declaration of the function, when this function is made as a friend of the first class, compiler wont be aware of that particular name since the class is not yet defined. So we have to simply give a “forward  declaration” of the second class above the first class so that  compiler is  aware of the future coming class. Just see the below example.
//dealer_customer.h
#include <iostream>
using namespace std;
class Customer;
class Dealer    {
        private:
                char Dealer_Name[20];
                const int Dealer_Id;
                int Price;
                float Comm_Rate, Comm_Car, Total_Comm;
        public:
                Dealer(char *n, int i) : Dealer_Id(i)   {
                        strcpy(Dealer_Name, n);
                        Comm_Rate = Comm_Car = Total_Comm = 0;
                }
                friend void Printer(Dealer&, Customer&);
};

class Customer  {
        private:
                char Customer_Name[20];
                const int Reference_No;
        public:
                Customer(char *n, int i) : Reference_No(i)      {
                        strcpy(Customer_Name, n);
                }
                friend void Printer(Dealer&, Customer&);
};


//dealer_library.cpp
#include "dealer_customer.h"

void Printer(Dealer &John, Customer &Smith)     {
        cout << "Dealer Details" << endl;
        cout << "Dealer Name" << John.Dealer_Name << endl;
        cout << "Customer Details" << endl;
        cout << "Customer Name" << Smith.Customer_Name << endl;
}

//dealer_application.cpp
#include "dealer_customer.h"
int main()      {
        Dealer John("John Abraham", 1);
        Customer Smith("Stephen Smith", 12);

        Printer(John, Smith);

        return 0;
}

One thing we can clearly understand here is since friend functions are global functions it will never have this pointers like our normal member functions.

We will see the real application of friend function in our later classes.
Now lets go back to our encapsulation. As an added feature or I should say to enhance the efficiency of encapsulation, there was another feature introduced in C++ known as operator overloading. Lets see what it is ?

Operator overloading :
            Like most of the programming languages, C++ supports a set of operators which works well with  built in data types. But in C++ most concepts are oriented towards objects rather than built in types. For example, complex arithmetic, matrix algebra, character strings etc can be implemented using class in C++. To do operations on the objects of these type of classes, we cannot use the operators provided by the language since they work only with built in data types. One way of doing this is writing our own functions doing such operations.
For example, lets say I have to add two objects and assign it to another. One way of doing it is I can write an Add function which takes the objects as arguments and which returns the added values. Ie)
            O1 = O2.Add(O3)
Perfectly possible right. but the problem with this type of writing functions is first of all unlike operators the functions written by us have to be invoked explicitly and more over if we are not providing proper function names, your program will ultimately become un readable or I should say readability will decrease. So in this type of cases using operators instead of user defined normal function will have real importance.
            So what we are going to do here is, since our operators are currently working only with built in data types we are going to re define our operators so that it works with user defined objects also. At the same time the old properties of the object ie) working with built in data types will be retained. Or in simple words we will overload the operator to work  with user defined objects. This is known as operator overloading.
            Operator overloading is achieved using operator functions. The syntax of operator functions is
            Return type operator # (function arguments)
            {
                        //definition of the function
            }
Most of the operator’s operator functions can be written either   as member functions of global functions. But if written as global functions, it should be made as a friend of your class.

We will take one example each from different category of operators and we will see how to write the operator functions for each.
Lets come out of the car dealer ship system for this example since we may not get any thing meaning full there in which we can do operations. So for operator overloading lets take a class called complex as an example which will represent a normal complex number with a real part and imaginary part.
           
Binary + : As member functions

//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 &);
                double Return_Real();
                double Return_Imaginary();
};

//complex_library.cpp
#include "complex.h"

Complex Complex :: operator + (Complex &obj)    {
        Complex Temp;
        Temp.Real = Real + obj.Real;
        Temp.Imaginary = 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);
        Complex O3(3.3, 4.4);

        O1 = O2 + O3;

        cout << O1.Return_Real() << endl;
        cout << O1.Return_Imaginary() << endl;

        return 0;
}

           
Binary + : As global functions

//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&, Complex&);
};


//complex_library.cpp
#include "complex.h"

Complex operator + (Complex &obj1, Complex &obj2)       {
        Complex Temp;
        Temp.Real = obj1.Real + obj2.Real;
        Temp.Imaginary = obj1.Imaginary + obj2.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 + O3;

        cout << O1.Return_Real() << endl;
        cout << O1.Return_Imaginary() << endl;

        return 0;
}

Concluding the binary operators : when written as member function, binary operator function will take one argument and the other object will be passed to the operator function through this pointers. Where as if it is written as global functions, since there is no this pointer for global functions, both the object should be passed as arguments to the global functions.

            
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