DAY – 8
Till yesterday’s class we have
seen features added along with member functions of the class to make the
encapsulation more efficient. In today’s class we will c few features added
along with data members of the class which in turn increases the efficiency of
encapsulation.
The
two features we are going to c in today’s class is static and constant.
Static members:
You might have
learnt about static data members in your C language right. The same old theory
is applicable in C++ also. Lets take an eg:
int add();
main()
{
int
c = add();
cout
<< c << endl;
c = add();
cout
<< c << endl;
c = add();
cout
<< c << endl;
}
int add()
int
i = 0;
i++;
return
I;
}
{
If you see the output here , you
can see that all the three cout statements prints 1 only. This is because, in
the function add, i is declared as a local variable which gets constructed when
the function is invoked and which gets destroyed when the function ends. A
slight modification in the above program changes the entire output. For eg:
int add();
main()
{
int
c = add();
cout
<< c << endl;
c = add();
cout
<< c << endl;
c = add();
cout
<< c << endl;
}
int add()
{
static int i = 0;
i++;
return i;
}
If you notice the output here,
you can c that it will print you 1, 2 and 3. So what s happening here.
At this point,
you should remember the basic rules of static variables. Static members gets
memory only once in your program. The memory for static variables will be
allocated in the data segment and the allocation will be taken care of by the
compiler. Now correlating these rules to the above program : here the variable
i gets memory only once. That means, it wont be destroyed when the add function
ends. Its scope is till the program / main ends. So each and every time the
function is called, the same memory location allocated first time will be
getting manipulated giving us the appearance that the variable i retains its
value after each and every function call.
We are going to
apply the same rules to our class data members and function members. Lets deal
with the data members and function members separately.
Static data members:
Usually
members of a class will be getting memory at the time of creation of objects.
Ie) each and every object will be having its own copies of data members. When
the data member of a class is made as static, since memory can be allocated
only once, each and every object will be forced to share this single memory
location. Since it is a shared property, none of the objects will consider this
static variable at the time of allocation of memory. That means static
variables wont be getting memory at the time of creation of objects. So it is
our responsibility to explicitly instruct our compiler to take care of the
memory allocation. To do this, we have to re-declare the static variable
outside the class. First lets c a sample program to c how we have to re-declare
it. Then we will move on to an application program.
class myclass {
private:
Static
int a;
Int
b;
public:
myclass(int
p, int q) {
a
= p;
b
= q;
}
void
display() {
cout
<< a << endl;
cout
<< b << endl;
}
};
int myclass :: a;
So here we are telling our
compiler that the variable a belonging
to the scope of myclass is a static variable. So please take care of its memory
allocation. Lets try to write the main of this program.
main()
{
myclass
obj1(10, 20);
obj1.display();
myclass
obj2(100, 200);
obj2.display();
obj1.display();
}
If you notice the output here :
10
20
100
200
100
20
You can see that the changes made
by one object on the static variable is directly getting reflected on the
other. As you can guess, it is because the memory allocated for static variable
is shared between obj1 and obj2.
We
can apply the concept of static to our function members also.
Static member functions.
Just
like static data members, static member functions are also independent of the
objects. And the most interesting thing about static function members is it can
access only static data members. This is because, since the static member
functions are independent of the objects, it is perfectly legal to access them
even before the creation of objects. The normal data member of the class gets
memory only at the time of creation of objects. So naturally static member
functions cannot access them before creating objects. The only data member who
gets memory even before the creation of objects is static data members. So the
static member functions can access only static data members.
Or simply
stating, since static member functions are independent of the object, there
wont be any this pointer associated with it. So it cannot access any data
member which has a this pointer. The syntax for static member function defined
inside the class is
class class_name {
public:
Static return type
function name(function arg) {}
};
When declared inside and defined
outside, the syntax of static member function changes a little.
class
class_name {
public:
static
ret-type fun-name(fun-arg);
};
Ret_type
class name :: fn-name(fun arg) {}
If you notice you can see that
static keyword have to be supplied only in the declaration and not in the
definition.
Let’s learn
about constant data members and function members also. Then we will come to an
application program.
Constant data members:
As
you know, the members defined as constant cannot be modified in the program.
The same rule is applicable to data members made as constant in the class. But
while declaring a variable as constant there are few things which you have to
worry about. When you declare a variable as constant, you need to initialize it
at the time of declaration itself. Else it will throw you an error. But when
you declare a variable inside the class, it is not legal to initialize it there
since there wont be any memory allocated till we create an object. Or simply
saying, class is just a plan / template. So initializing at the time of declaration
inside the class will be like putting mud on the paper where you have drawn the
house plan. So what to do? In this type of situations we have to seek the help
of a new technique termed as initialization through member initializer list. The syntax is
Constructor()
: var(), var() {}
Lets take an eg:
class myclass {
private:
Const
int x;
Const
int y;
public:
Myclass()
: x(10), y(20) {}
};
main()
{
myclass
obj;
}
Here x and y are constant
variables initialized through member initializer list. This is the only way you
can initialize a constant variable.
There
is one more application for this member initializer list. It is regarding
reference variable. We have already learnt that a reference variable declared
needs to get initialized at the time of declaration itself. So a variable
declared as reference to another variable in the class needs to get initialized
at the time of declaration. Since it is not practically possible we have to
seek the help of member initializer list. Consider the following eg:
class myclass {
private:
int
x;
int
&y;
public:
myclass()
: y(x) {
X
= 10;
}
};
main()
{
myclass
obj;
}
Again this is the only way we can
initialize a reference variable inside the class.
Lets go back to our discussion
regarding constants. The keyword const can be applied along with member
function also and we call them as constant member functions.
Constant member functions:
The
syntax of constant member functions when defined inside the class is
class class-name {
public:
Ret-type
fun-name(fun-arg) const {}
};
Again the syntax changes slightly
when declared and defined outside.
class class-name {
public:
Ret-type
fun-name(fun-arg) const;
};
Ret-type class-name ::
fn-name(fn-arg) const {}
If you notice you can see that
unlike static functions, const keyword needs to be present in the declaration
as well as definition.
The
specialty of constant member functions is that it can access any variables but
it cannot modify any variables. So in constant member functions, the this
pointer will be acting as a constant pointer to constant object. Because of
this reason, constant member functions are termed as accessors.
Now lets combine
static’s and constants and lets try to do the abstraction and encapsulation of
an entity known as Car. Lets keep the class diagram as below.
In
the above abstraction we can make seating capacity and fuel capacity as
constants. Since discount is something which is going to be common for all the
cars, we can make discount as static.
Among
the behaviours, since discount should be fixed or viewed irrespective of a
particular car, both the functions can be made as static where as since all
other functions are simply acting as display functions or accessors we can make
it as constants.
The
encapsulation of the above entity can be done as follows.
//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;
};
//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;
}
//car_application.cpp
#include "car.h"
int main() {
Car Santro("Hyundai",
"Santro", 4, 35, 400000.00);
Car :: Set_Discount(0.10);
cout << "Displaying
Discount" << Car :: Return_Discount() << endl;
cout << "Car Details"
<< endl;
cout << Santro.Return_Make()
<< endl;
cout <<
Santro.Return_Model_Name() << endl;
cout << Santro.Return_Price()
<< endl;
return 0;
}
Now
lets assume that while displaying price, I have to change it according to the
discount and then return it. Is it possible ? no right: it is because return
price() is a constant function which is not able to modify any value. But even
this can be made possible in C++. Ie) I can make a constant function to modify
a non constant value and it is achieved using something known as mutable.
Mutable:
A
variable declared as mutable is modifiable by a constant member function and it
acts as a normal data member for other functions. So applying this concept and
modifying the above class.
Lets
modify it and lets see the encapsulation of it
//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;
mutable 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;
};
//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 {
if(Discount > 0.0) {
Price = Price - (Price *
Discount);
return Price;
}
else
return Price;
}
//car_application.cpp
#include "car.h"
int main() {
Car Santro("Hyundai",
"Santro", 4, 35, 400000.00);
Car :: Set_Discount(0.10);
cout << "Displaying
Discount" << Car :: Return_Discount() << endl;
cout << "Car Details"
<< endl;
cout << Santro.Return_Make()
<< endl;
cout <<
Santro.Return_Model_Name() << endl;
cout << Santro.Return_Price()
<< endl;
Car :: Set_Discount(0.0);
cout << "Without
discount" << Santro.Return_Price() << endl;
return 0;
}
0 comments:
Post a Comment