|
|||||
CS201
Introduction to Programming
Lecture
Handout
Introduction
to Programming
Lecture
No. 38
Reading
Material
Deitel
& Deitel - C++ How to
Program
Chapter.
11, 7, 3
11.6.4,
page 181, 7.7,
3.10
Summary
46)
User
Defined Manipulator
47)
Examples
of user defined manipulator
48)
Static
keyword
49)
Static
Objects
50)
Static
data members of a
class
Today, we
will discuss the concepts
like `user-defined manipulators'
and `static
keywords'.
Despite being considered
minor subjects, these become
very important while
carrying
out complex programming. Let's
start with `User-defined
manipulators'.
User
Defined Manipulators
We have
talked a lot about the manipulators
that are provided with the
streams in the
C++.
These are similar to `setw'
function, used to set the
width of the output. These
are
employed as
inline like cout
<< endl << i; Remember
that these functions work
for only
the
immediately next output. How
can we write our own
manipulator? To determine it, it
is better
to understand what parameter-less
manipulators are? These are
the manipulators
without
any parameter like endl.
This is a
parameter-less built-in manipulator that
inserts
the
new line besides flushing
the buffer. If we want to
write our own manipulator,
how
can we do
this? In case of operator overloading, it
is pre-requisite to know that where
the
operator
will be used, what will be
on its left-hand and right-hand sides. On
reviewing the
manipulators,
you will find a stream
object, normally on the left-hand side.
Here, we are
talking
about ostream, an output
stream. So that object will be
cout. The
cout
will
take
this
manipulator to carry out some
manipulation. These are
written in cascading style as
cout
<< manipulator << "some data"
<< endl. With
this cascading style, you
can get a
hint
about the operation of this
manipulator and its requirements.
The point is, the
left-
Page
481
CS201
Introduction to Programming
hand
side is going to be ostream
object
that will call the
manipulator. What will be
passed to
the manipulator and what
will be the return
type.
Normally
on the right-hand side of the
manipulator, we have another stream
insertion
operator
i.e. <<. Here we are considering a
parameter-less manipulator, that is
no
argument
or number will be passed to
it. It may be something like inserting a
tab between
two
numbers for formatting or a manipulator
to end the line or to make a
sound of bell
and so
on. The left hand
side is ostream
object.
There are no other
parameters. The
right-
hand
side is normally a stream insertion
operator. We use it as cout
<< manipulator
which is
itself an action. We overload the
stream insertion operator in such a
way that the
cascading
works. So we return an ostream
object.
More accurately, a reference
to
ostream
objects
is returned. Manipulator is also going to
be used in the same way, so
that
it
returns a reference to an object of type
ostream.
Therefore we want to return
the cout
object or whatever
stream we are using. Secondly it
also needs the object that
is calling it.
Here we
are not talking about
our own class. ostream
class is
built-in and not under
our
control. So it
can not be modified. We can
only extend it by defining external
things. So
it is not
a member function or member operator, but
only a standalone operator.
Normally
the
declaration of this manipulator is
as:
ostream&
manipulator_name (ostream& os)
This is
also not a friend function.
We cannot define friends for the
classes that are
already
written
and not in our control. The
argument os
here is
the same object which is
calling
this
function. We have to explicitly
declare it. After this, we
have to define this.
Definition
is just as another function.
You can always write
whatever you want inside
the
function.
But we have to look at the
spirit of the manipulator. When we are
talking about
the
spirit of the manipulator, it means
that the manipulator should
only do something
regarding
output and return. It is normally
very simple. Its return type
is ostream
object.
In case
of tab character, we can
write as return os <<
`\t'; It can be
bell or something
else. We
can write useful manipulators to leave
single or double blank lines or
formatting
the
strings etc. Remember that
it has to return a reference of object of
type ostream.
It
automatically
gets that object as parameter
passed in to the
function.
Examples of
user defined
manipulator
Here is
the sample program using the
manipulators.
/* A
small program which uses the
user defined manipulators.
*/
#include
<iostream.h>
#include
<stdlib.h>
// Gives System
Beep
ostream
& bell ( ostream & output ) //
Manipulator
{
Page
482
CS201
Introduction to Programming
return
output << '\a' ;
}
// Gives
Tab
ostream
& tab ( ostream & output
)
//
Manipulator
{
return
output << '\t' ;
}
// Takes
the cursor to next
line
ostream
& endLine ( ostream & output ) //
Manipulator
{
return
output << '\n' << flush
;
}
void
main ( )
{
cout
<< "Virtual " << tab <<
"University" << bell << endLine ; // Use
of Mainpulator
system (
"PAUSE" ) ;
}
Lets
see another example of matrix
using the user defined
manipulators for displaying
the
matrix on
the screen.
Here is
the code:
/*
A small
program showing the use of
user defined manipulators.
The
display function of matrix is
using these manipulators to
format
the display.
*/
#include
<iostream.h>
#include
<stdlib.h>
#include
<iomanip.h>
//
definition of class
matrix
class
Matrix
{
private:
int
numRows;
int
numCols;
float
elements[3][3];
public:
//
constructor
Matrix(int
rows = 0, int cols = 0)
Page
483
CS201
Introduction to Programming
{
numRows =
rows ;
numCols =
cols;
}
// overloading
the extraction and insertion
operators
friend
ostream & operator << ( ostream
& , Matrix & );
friend
istream & operator >> ( istream & ,
Matrix & );
//
defining the user defiined
manipulators
friend
ostream & spaceFirst ( ostream &
);
friend
ostream & spaceBetween ( ostream
& );
friend
ostream & line ( ostream &
);
friend
ostream & newLine ( ostream &
);
friend
ostream & star ( ostream &
);
friend
ostream & sound ( ostream &
);
};
//defining
the operator >>
istream &
operator >> ( istream & input ,
Matrix & m )
{
for (
int i = 0 ; i < m.numRows ; i ++
)
{
for (
int j = 0 ; j < m.numCols ; j ++
)
{
input
>> m.elements [ i ] [ j ] ;
}
}
return
input;
}
//defining
the operator <<
ostream
& operator << ( ostream & output ,
Matrix & m )
{
for (
int i = 0 ; i < 60 ; i ++ )
{
if ( i == 30
)
{
output <<
"Displaying The Matrix"
;
}
else
{
output <<
star ;
}
}
output
<< newLine;
for (
int r = 0 ; r < m.numRows ; r++
)
{
Page
484
CS201
Introduction to Programming
output <<
spaceFirst << line;
for (
int c = 0 ; c < m.numCols ; c++
)
{
output <<
spaceBetween << m.elements [ r ] [ c ] <<
sound << spaceBetween ;
}
output <<
spaceBetween << line;
output <<
newLine;
}
output
<< newLine;
return
output;
}
//defining
the user defined manipulator, inserting
the space
ostream
& spaceFirst ( ostream & output
)
{
output
<< setw(33);
return
output;
}
//defining
the user defined manipulator, inserting
the space
ostream
& spaceBetween ( ostream & output
)
{
output
<< setw ( 4 );
return
output;
}
//defining
the user defined manipulator, inserting
the | sign
ostream
& line ( ostream & output
)
{
output
<< "|" ;
return
output ;
}
//defining
the user defined manipulator, inserting
the new line
ostream
& newLine ( ostream & output
)
{
output
<< endl;
return
output;
}
//defining
the user defined manipulator, inserting
the *
ostream
& star ( ostream & output
)
{
output
<< "*" ;
return
output ;
}
//defining
the user defined manipulator, making
sound
ostream
& sound ( ostream & output
)
{
output
<< "\a" ;
Page
485
CS201
Introduction to Programming
return
output ;
}
// the
main function
int
main ( )
{
// declaring a
matrix of 3*3, taking its
input and displaying on the
screen
Matrix
matrix( 3, 3);
cin
>> matrix;
cout
<< matrix;
system("PAUSE");
return
0;
}
The
output of the program:
3
5
1
8
7
6
2
5
2
******************************Displaying
The
Matrix*****************************
| 3 5 1 |
| 8 7 6 |
| 2 5 2 |
Press
any key to continue . .
.
Static
keyword
We have
been using static keyword in
our examples. What is the
meaning of static?
The
word
refers to something that is stationary,
stopped and not moveable.
What are the
types
of these
variables, declared as static?
How can we make use of
them? Static as the
word
implies
are variables which exist
for a certain amount of
time, much longer than that
by
ordinary automatic
variables. Let's consider
the example about the
lifetime of data
variables.
One of the variable types is
global variable. Global variables
are those that
are
defined
outside of main. They are
written as standalone statements
before main function
as int
i; the
variable i
is a
global variable. It is not only
accessible in main but also
in all
the
functions. They can assign some
value to i
or
obtain the value of i. Global
variables
come
into existence whenever we
execute the program and
the memory is allocated for
i.
It exists
all the time when
the program is running. At the
end of the program
execution,
the
memory will be de-allocated
and returned to the
operating system. So it has a
very
Page
486
CS201
Introduction to Programming
long
lifetime. We need a value
which exists for the complete execution
of the program
and is
available in all the functions. We use
global variables. It is not a
good idea to do
that
unless it is absolutely necessary. The
major plus point of these
variables is that
these
are
accessible from everywhere in the
program. The inconvenience is
that theses
variables
are visible in those functions
too which does not
need them.
Suppose,
we have a global variable i
declared
as int
i; and in
some function we are
writing a
for
loop as
for(i
= 0; i < n; i++); Now
which i
is
being used here. This is
the
variable
i,
declared as global. This global
i
may
have some valuable value,
like the
number of
cars or the number of
students etc. Here, in the
function when we run the
loop,
the
value of i
will be
changed. The global
variables have this bad
habit of being around,
even
when we don't need them.
What will happen if we
declare another i
variable
inside
the
function? A local variable will be
created inside the function at
run time and
the
global
i
is
not going to be accessible. But this
can be very subtle and
hard to track
programming
errors. These are not
syntax errors but logical
ones. So beware of using
too
many global
variables. Now have a look
on the other side of the
picture. While writing
functions, we
pass values to them. So instead of
passing the value of i
again
and again,
we
declare it as global. Now it is available in
the function, leaving no need of
passing it.
Let's
now come to the next
variety of variables. The
variables, defined in the
main
function
are local to the function
main. It means that they
are accessible in all parts
of the
main
function. Their values can
be assigned, used in computations and
later displayed.
When we
enter some function other
than main, these variables
are not accessible
there.
They
are hidden. The global
and the local variables,
declared in a function are
visible.
The
arguments passed to a function,
are also visible. We pass
the parameters
through
stack.
Parameters are written on
the stack. Later, the
function is called which reads
from
the
stack and makes a temporary copy
for its use. The
variables, declared and used
inside
the
function are called automatic variables.
They automatically come into
being when the
function
is called. When the function finishes,
these variables are
destroyed. So automatic
variables
are created constantly and
destroyed all the time.
Here, we are talking
about
variables
ordinary as well as user defined
objects. Their behavior is
same. They are
automatic
when the function is called,
memory is allocated normally on
the stack at the
same
time and used. When the
function exits, these
variables are destroyed.
What
happens
if we want that when the
function exits, some value,
computed inside the
function,
is remembered by the function
and not destroyed. This
should not be visible
by
the
other parts of the
program.
Let's
consider the example of a refrigerator. When we
open the door of a refrigerator,
the
light
turns on and we can see
the things inside it. However, on closing
the door, the
light
turns
off. Do we know that light
is off because whenever we
open the door the
light is on.
When we
close the door what is
inside. We do not know. May be things
magically
disappear.
When we open the door,
magically, the things are at their
position. You can
think of
this like a function. When we enter in
the function, these automatic
variables are
available
there and visible. When we
came out of the function, it
is like closing the
door
of the
refrigerator and the light is
turned off. We cannot see
anything. Function goes one
step
ahead of this and it
actually destroys all the
variables. Whereas, in the
refrigerator,
Page
487
CS201
Introduction to Programming
we know
that things are there.
Somehow we want the function
to behave like that.
Outside
the refrigerator, these things are
not available. We can not
access them. Let's
say
there is
a bottle of water inside the refrigerator. You
open the door and
place it some
other
place. Next time, when
you will open the
door, the bottle is seen at
the same
position
where you have moved it. It
would not have moved to some
other position. If
you think
of automatic variables, suppose we say
inside the body of the function
int
i =
0;
Every
time the function is called
and you go into the
function where i
is
created. It has
always
the value 0 to start with
and later on we can change
this value.
What we
want is that whenever we go
back into the function,
once we call the
function
like we
open the door of the
refrigerator and move the bottle to
some other place
and
close
the door. So we made one
function call. Next time,
when we call the function,
the
bottle is found in
its new place. In other
words, if we have defined an
integer variable, its
value
will be set at 10 in the
function when we return from
the function. Next time
when
we call
the function, the value of
that integer variable should be 10
instead of 0. We want
somehow to
maintain the state of a variable. We
want to maintain its
previous history.
If we
declare a global variable, the
state would have been
maintained. The global variable
exists
all the time. Whatever
value is set to it, it is
there and accessible from
any function.
The
drawback is that variable exists even
when we don't want it.
Static keyword allows
us a mechanism
from getting away of the downside of
the global variables and
yet
maintaining
a state inside a function. When we visit,
it is found out what are its
values
before
that we go ahead with this
value. For this, whenever we
declare a variable inside
the
function, static
keyword
is employed before the variable
declaration. So we write
as:
static
int i;
That
declares i
to be
a static integer inside the function.
Think about it. Should we
declare
static
variables inside the main function?
What will happen? `main'
itself is a function so
it is not
illegal. There is no objective of doing
this in main because main is
a function
from
where our programs start and
this function executes only
for once. So its state is
like
an ordinary variable,
declared inside main. It is only
relevant for the called functions.
We
write
inside the function as static
int i; while
initializing it once. It will be
created only
once
irrespective of the number of function
calls. Now once it is created, we
increment or
decrement
its value. The function
should remember this value.
The programmer may go
out of
the function and come
back into it. We should
get the value that
should be same as
that at
the time of leaving the
function. It is necessary for
the static variables that
when
these
are created, they should be
initialized. This initialization
will be only for once
for
the
complete life cycle of the
program. They will be initialized
only once.
Here, we
have to take care of the
subtle difference. In case of ordinary
variable
declaration,
we should initialize them before
using. If you have to
initialize an int
with
zero, it
can be written as int
i; and on
the next line i = 0;
But in
case of static variables,
we have
to use a different type of
initialization. We have to use it as
static
int i = 0; It
means
that creation of i
and
the allocation of memory for
it takes place simultaneously. It
is
initialized and the value 0 is
written. This is initialization
process. If somewhere in
the
Page
488
CS201
Introduction to Programming
function,
we have statement i =
10; it will
not be treated as initialization.
Rather, it is an
assignment
statement. Here we want that as
soon as the variable is created, it
should be
initialized.
This initialization will be
only for once for
the lifetime of the program
and it
takes
place when first time we
enter in to the function.
However we can manipulate
this
variable as many times
as we want. We can increment or decrement
it. However, it will
remember
its last value. How
does this magic work? So
far, we have been talking
about
the
stack and free store.
There is another part of
memory, reserved for the
variables like
static
variables. On the stack, automatic
variables are being created
and destroyed all
the
time.
The heap or free store
has the unused memory
and whenever we need memory,
we
can
take it from there and
after use return it.
This is the third part
which is static memory
area
where static variables are created
and then they exist
for the rest of the
program.
These
variables are destroyed on
the completion of the
program. So they are
different
from
automatic variables which are
normally created on stack. They
are different from
dynamic
variables that are obtained
from free store.
To prove
this whole point let's
write a simple program to fully
understand the
concept
and to
see how this works.
Write a small function while
stating that static
int i = 0; Here,
we are
declaring i
as a
static integer and initializing it
with zero. Then write
i++;
print
the value
of i
using
cout. Now
this function just
increments the value of i. This
i
is a
static
integer
variable inside the function. Now
write a main function. Write
a loop inside the
main
and call this function in
the loop. Let's say the
loop executes for ten times.
You will
notice
that whenever you go inside
the function, the value of
i
is
printed. The value of i
should be
printed as 1.2.3...10. If you remove
the word static from the
declaration of i,
you will
notice that every time 1 is printed.
Why 1? As i
is
now automatic variable, it is
initialized
with zero and we increment it
and its value becomes 1.
cout
will
print its value
as 1. When we
return from the function
i
is
destroyed. Next time when
function is called,
i
will be
created again, initialized by
zero, incremented by 1 and
cout
will
print 1. By
adding
the static keyword, creation
and initialization will
happen once in the life
time of
our
program. So i
is
created once and is
initialized once with the
value of zero.
Therefore
i++
will be
incrementing the existing value. At
first, it will become 1. In this
case,
function
will return from the
loop in the main
program,
call
this function again.
Now
its
value is
1, incremented by 1 and now
the value of i
becomes 2
and printed by cout.
Go
back to
main, call it again and so
on, you will see it is
incrementing the last value.
You
can
prove that static
works.
Here is
the code of the
program:
/* This
is a simple program. This shows
the use of static variables inside a
function.
*/
#include
<iostream.h>
void
staticVarFun();
void
nonstaticVarFun();
void
main(void)
Page
489
CS201
Introduction to Programming
{
cout
<< "\nCalling the function
which is using static variable
\n";
for(int i
= 0; i < 10; i++)
staticVarFun();
cout
<< " \nCalling the function
which is using automatic variable
\n";
for(int i
= 0; i < 10; i++)
nonstaticVarFun();
}
//
function definiition using static
variables
void
staticVarFun()
{
static
int i = 0;
i++;
cout
<< "The value of i is:" << i <<
endl;
}
//
function definiition using automatic
variables
void
nonstaticVarFun()
{
int i =
0;
i++;
cout
<< "The value of i is:" << i <<
endl;
}
The
output of the program:
Calling
the function which is using
static variables
The
value of i is:1
The
value of i is:2
The
value of i is:3
The
value of i is:4
The
value of i is:5
The
value of i is:6
The
value of i is:7
The
value of i is:8
The
value of i is:9
The
value of i is:10
Calling
the function which is using
automatic variables
The
value of i is:1
The
value of i is:1
The
value of i is:1
The
value of i is:1
The
value of i is:1
Page
490
CS201
Introduction to Programming
The
value of i is:1
The
value of i is:1
The
value of i is:1
The
value of i is:1
The
value of i is:1
Static
Objects
Let us
look at some more uses of
this keyword. As mentioned earlier that
the user defined
data
types are the classes
and objects that we created.
These are now variables as
for as
we are
concerned. If these are
variables, then we can
declare them as static. Now we
have
to be careful
when we think about it. When
we declared static int, we said
that it should
be
initialized there. We initialized it
with zero. What is the
initialization of objects? We
have
defined a class and instantiated an
object of that class. So we can
say something like
vehicle A
or truck B where vehicle and
truck are the classes
which we have defined.
`A'
and
`B' are their objects, being
created in some function or
main. When are these
objects
initialized?
You know that the
initialization is done in constructors.
So normally C++
provides
a default constructor. Here we have to
write our own constructors
as
initialization
can happen only once, if
declared static. Again we are
talking about these
static
objects inside a function instead of
the main. These objects
should maintain their
values
while getting out of the
function.
Whenever
we create a static object, it must be initialized.
Most of the time, we want
that
when
the object of our class is
created, its data members
should be initialized by
some
value.
For this purpose, we have to
provide a constructor so that whenever an
object is
created,
its data members are
initialized. Only then it
will work. Otherwise we will
have
problems.
We may want to do as truck A,
but our constructor takes
some arguments.
Now
how this object will be
created. How many wheels this
truck will have? How
many
seats
will be there? We have a
solution to overcome this problem.
Define a constructor
which
takes arguments and provides
the default value to it simultaneously. If
you provide
a
constructor with default values,
then the object which is
created will automatically
get
these
values. If you write truck A(4,
6),
there may be some
constructor which
will
initialize
it with 4 wheels and 6 seats.
But the point to remember is
if you ever go to use
a
static object, it is
necessary to provide a constructor with
default arguments so that
the
object
which you have created is
initialized properly. Other than
that the whole
behavior
of a static object is
exactly the same as we have
a static variable of an ordinary data type
or native
data type. Static variable means
maintaining the state of a variable. It
exists and
lives
around even when we are
outside the function. It is an
alternative to using a global
which
exists even when we don't
want it. Now we try to
learn about the destructors
of
static
objects. If you create an object inside a
function as truck
A,
when the function
finishes,
the object A
will be
destroyed. Destructor for this static
object will be called.
To prove
this write a class, inside
the constructor. Also write
a cout
statement
which
should
print `inside the constructor of
'and the name of the object
which will be passed
as
an
argument. In the destructor
write a cout statement as cout
<<" Inside the destructor of
Page
491
CS201
Introduction to Programming
" <<
name, where
name will tell us that
which object is this. Now experiment with
it.
Declare a
global variable of this class
before main as truck
A(`A'). When
the constructor
for
this object is called the line
`Inside the constructor of A'
will be displayed. Now
within
the main function, declare
another object as ordinary variable i.e. truck
B(`B').
Its
constructor
will also be called. You
will see it. Write a
small function and create
another
object
within that function as truck
C(`C'). Define
another function and declare
a static
object in it as
truck
D(`D'). Call
these two functions from
main. Now compile
and
execute
this program, as we have
written cout
statements
inside the constructor
and
destructor.
Now you will be able to
determine which object is being
created and which
one
being destroyed. Here you
will also notice that first
of all global object A
will
be
created.
There is going to be a line `Inside
the constructor of object A'.
After that, object
B
will be
created, followed by the
display of constructor cout
line.
From main, we are
calling
function F
which is
creating object C. So object
C
will be
created then. What
next?
The function F
will
finish and the control go
back to main. If the
function F
finishes,
its local data will be
destroyed. So the object C
will be
destroyed. Here, you
see
it on the
screen `Inside the
destructor C'. After this
the function G
will be
called and we
will
have `Inside the constructor
for D'. This object D is a static object.
Now when the
function
G
finishes,
you will not see
the destructor line for
object D. After
this, the main
function
finishes and the destructors
will be called for objects
A
(which is
global), object
B
(which is
inside the main) and object
D
(which is
created as static inside the
function
G). In
which order these will be
called?. If you look at this
very simple program, you
will
find
that the last object to be
created was the static object inside the
function G.
Should
that
deleted first i.e. the
destructor of object D
should be
called? Well actually not
true,
the
local variables of main
function will be first
destroyed. Static objects remain
for
longer
period of time. Later, the static object
D
will be
destroyed and the thing
finally
destroyed
is the global object, which was
created first of all. You
will find that
the
destructor
for object A
is
called. With this exercise,
you will know the
sequence in which
things
are created and destroyed.
Another thing that you
will notice is that when
the
function
G
finishes
the static object is not
destroyed.
The
code of the program;
// An example of
static objects, notice the sequence of
their creation and
destruction
#include
<iostream>
//
defining a sample
class
class
truck {
private:
char
name; // Identifier
public:
//
constructor displaying the output
with the object name
truck(char
cc):name(cc) {
cout
<< "inside the constructor of "
<< name << endl;
}
// distructor
displaying the output with
the object name
~truck()
{
Page
492
CS201
Introduction to Programming
cout
<< "Inside the destructor of "
<< name << endl;
}
};
//
defining a global object
truck
A('A');
// a
simple function creating an
object
void
f() {
truck
C('C');
}
// a
simple function creating a static
object
void g()
{
static
truck D('D');
}
// main
function
int
main() {
// an ordinary
object
truck
B('B');
//
calling the functions
f();
g();
}
The
output of the program:
inside
the constructor of A
inside
the constructor of B
inside
the constructor of C
Inside
the destructor of C
inside
the constructor of D
Inside
the destructor of B
Inside
the destructor of D
Inside
the destructor of A
Lets
recap these concepts. When
you declare a static variable (native
data type or object)
inside a
function, it is created and
initialized only once during
the lifetime of the
program
and
therefore it will be destroyed or
taken out of memory only
once during the lifetime
of
the
program. So it is a good way of
maintaining state. It is an alternative to
using a global
data type
which has some side
effects. In the main, we can
write static variables but it is
a
meaningless
exercise because these are
exactly like ordinary variables inside
main.
Static
data member of a
class
Lets
talk about the keyword
static inside the class. Static variables
are used to maintain
state. We
are talking about the
state in which we left the
function. While extending
the
concept,
we will go inside an object. Here, we should
find certain things left
exactly the
Page
493
CS201
Introduction to Programming
way
they were initially. So now we
are talking of static data
members inside a class.
What
does it mean?
Literally
speaking, the word `Static'
means the stationary
condition of things. Stationary
for
object or class? Here it will be
stationary for the class.
That means that static data
will
be
created once and initialized
once for that class.
Therefore it is not related to
the objects
of that
class. There is only one
copy of the static data member inside a
class. The copy is
not
repeated for the objects.
Whenever we create an object of a class,
the complete data
structure
is copied for that object
and there is one copy of functions
which the objects
may
use. Static members are single
for the whole class in
the static memory area. It
will
not be
repeated whenever we create an object of
the class.
Now
the question arises when it
will be created? When it will be
initialized? And when
it
will be
destroyed? Now these are on
class level and not on object
level. To understand
this, we
have to talk about the
lifetime of the static data member.
The lifetime of the
static
data member of a class is the
lifetime of the program. In
other words, when
you
include a
class in the program as a class
definition, the memory is
allocated for its
static
data
members. We have some
techniques to initialize it. We
initialize it only
once.
Initialization
is done at file scope which
means almost at the global
scope. We initialize it
outside
of the main. The memory is
allocated for these static
members. No other copy
can
be
created for them. Therefore we
can create and initialize
them outside of main. There
is
no object so far.
How can we initialize its
static data members?
Suppose
we have a class truck
as:
class
truck{
public:
int
wheels;
int
seats;
}
Now we
refer the data members
with the object as:
truck
A;
A.wheels
= 6;
A.seats =
4;
That's a
way to refer to a data member. Here we
are saying that we have some
static data
member of
class and the object A
has
not been created yet. But we
have the memory
for
the
static members. Now we want to
initialize that memory. How
can we do that? We do
this by
using the scope resolution
operator (::) and on its
left hand side, we have
class
name
and not the object name. On
the right side, we write
the name of the static
data
member.
Suppose we have some static
integer data member i
in
the class truck, so we
can
write it
as:
truck::i
= 10;
Page
494
CS201
Introduction to Programming
This
initialization is taking place at
file scope outside of the
main .As it is happening
only
once in
the program, it will not be
executed again. It is being
initialized once for
the
class.
You can create as many
object as you want. Objects
can read and change
that
value.
Static
data members of a class can
be public or private. The objects of
the class have
access to
them. They can manipulate it. But it is
created and initialized only
once. There
is a single copy of
these static data members
regardless of how many objects of
the class
you
create.
Let's
take a look at the problems having static
data members of a class.
Suppose we have
a class
as `savingsAccount'. We deposit money in
that account. Some profit is
also
earmarked
for it. Over a period of time,
bank declares the rate of
the profit. Profit rate
is
same
for all PLS accounts.
We have defined a class savingsAccount
which
have the
information
like person name, account
number, current balance etc.
We also have to keep
the
profit rate so that we can
apply that on the account. Do we
have different profit rate
of
every
account? No, the bank
has declared say 3% profit
rate. That will be applied to
all
the
PLS accounts. So we want
that the profit rate
should be defined at one
place. It should
be the
part of the class but
not defined for each object.
So it is a good place to use a
static
variable as a
data member of the class. We
can initialize it at file
scope as:
savingsAccount::profit_rate
= 3.0;
We will
write this before main
function. As soon as, we
compile the program and try
to
run
it, the space is created in
the static storage area. The
above statement will
initialize
that
static memory with 3.0. No
savings account has been
created yet. We will be
creating
saving
accounts (object of class savingsAccount) in
the main or some other
function as
account1,
account2, etc. This profit
rate will be available to every
account. We can
access
it
as:
account1.profit_rate;
and
can use it in computations. This is legal
but a bad usage. Why it is a
bad usage?
Suppose
we write as;
account1.profit_rate
= 4.0;
What
will happen? Does the
profit rate for only
account1
has
been changed? No. There
is
only
one copy of profit_rate for all
the objects of this class.
That means if an object
manipulates
the static data member, which it
can through the member functions
or
directly
depending on it is private or public. It is
actually modifying the value
of that
static
data member for all objects
of this class. So don't
assume that it will
change
profit_rate
for one object. It is a legal but a
bad usage. Always use it
with the class
name
and
not with the object. So you
should access it as savingsAccount::profit_rate. It
means
you
are resolving it at class scope. Be
careful while applying
it.
Page
495
CS201
Introduction to Programming
Let's
consider another example. We have a
class as student
and a
data member for how
many
students in the class. Now
every time, a student enrolls in
the course, we want
that
number of
students should be incremented.
Whenever a student withdraws,
fails or passes
out
from the course, the
number of students should be
decremented. We want this to
be
inside
the student
class.
How does it work? We define a static
data member as static
int
how_many;
and
initialize it to zero
as:
student::how_many =
0;
In the
constructor of the class we
write as:
how_many++;
This
way, whenever a student object is
created, how_many
will be
incremented.
Whenever
a student leaves the course,
its destructor should be called. We
will write in the
destructor
as:
how_many--;
So it's a
good way of keeping track of
how many objects of a particular type
exist at this
time
inside the program. To display
that we can write a member
function that will
display
`how_many'.
The merit of this technique
is that we have done all
this work inside the
class. We
did not use two
classes or global variable or go through
the source code to
count
the number of students.
Using these, you can
make your program more and
more
dynamic.
The usage of static is very import. So
you should understand it
clearly. Static is
maintaining
the state. The state
may be how many students
are in the class.
Today we
have covered the
parameter-less manipulators which will
return the ostream
object
and ostream
object is
passed as an argument to them. Then we
discussed about the
static
data, both at the ordinary
level and then the static
data members inside the
class.
These
are very useful. As you
write bigger and more
complex programs, you will
find
that
these concepts are very
useful. Again from a generic
prospective, you will
be
working
hopefully in your professional
career with many different
languages. You have
to
understand that every
language might represent the
static concept in a different
way.
But just
knowing that concept empowers
you and help you to
understand more complex
programming
languages as well.
Page
496
Table of Contents:
|
|||||