User Defined Manipulators-Introduction To Programming-Lecture Notes, Study notes of Computer Programming

A program is a precise sequence of steps to solve a particular problem. This course includes basic programming structure like loops, operator, memory allocation, reference, pointers etc. It teaches how to be a good programmer. This lecture handout is about: User, defined, Manipulator, Static, Keyword, Objects, Data, Member, Class, Function, Parameter, Stream, Object, Declaration, Argument

Typology: Study notes

2011/2012

Uploaded on 08/06/2012

anchal
anchal 🇮🇳

4.6

(9)

95 documents

1 / 15

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
454
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-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.
docsity.com
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff

Partial preview of the text

Download User Defined Manipulators-Introduction To Programming-Lecture Notes and more Study notes Computer Programming in PDF only on Docsity!

Lecture No. 38

Reading Material

Deitel & Deitel - C++ How to Program Chapter. 11, 7, 3

11.6.4, page 181, 7.7, 3.

Summary

  1. User Defined Manipulator
  2. Examples of user defined manipulator
  3. Static keyword
  4. Static Objects
  5. 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” << end l. With this cascading style, you can get a hint about the operation of this manipulator and its requirements. The point is, the left-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.

docsity.com

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 { return output << '\a' ; }

docsity.com

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++ ) { 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; }

docsity.com

//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" ; 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:

docsity.com

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, 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.

docsity.com

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 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

docsity.com

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: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is:

Calling the function which is using automatic variables The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is: The value of i is:

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.

docsity.com

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 ” << 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

docsity.com

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 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;

docsity.com

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;

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;

docsity.com