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.
0 comments:
Post a Comment