|
|
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 leftCS201
– Introduction to Programming
Page 482
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 righthand
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 483
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 484
{
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 485
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 486
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 487
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 488
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 489
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 490
{
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 491
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 492
” << 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 493
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 494
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 495
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 496
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. |
|
|
|