Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 144

Object Oriented Programming Lab

CEEN2231-L

Department of Computer Engineering

Khwaja Fareed University of Engineering and


Information Technology
Rahim Yar Khan, Pakistan
ii Contents
Contents

1 Lab 1:Review of CS101 & Arrays (1D and 2D) 1

2 Lab 2 Pointers in C++ 13

3 Lab 3:Strings in C++ 29

4 Lab 4:Structures I 49

5 Lab 5:Structures II 59

6 Lab 6:Object Orientation in C++ I 69

7 Lab 7:Object Orientation in C++ II 81

8 Lab 8:Friend Function & Classes, This Pointer, and static Variables 99

9 Lab 9:Operator Overloading 111

10 Lab 10:Inheritance 117

11 Lab 11:Introduction to Polymorphism and Abstract Base Classes 123

12 Lab 12:File Handling in C++ 133

iii
iv Contents
Chapter 1

Lab 1:Review of CS101 & Arrays


(1D and 2D)

1 # include <iostream . h>


2 i n t main ( ) {
3 short age ;
4 age = 23 ;
5 cout <<" The age i s =" <<age<<endl ;
6 return 0 ;
7 }

A class is a data type that you define. It can contain data elements, which can
either be variables of the basic types in C++ or other user-defined types. The data
elements of a class may be single data elements, arrays, pointers, arrays of pointers
of almost any kind or objects of other classes, so you have a lot of flexibility in what
you can include in your data type. A class can also contain functions which operate
on objects of the class by accessing the data elements that they include. So, a class
combines both the definition of the elementary data that makes up an object and
the means of manipulating the data belonging to individual instances of the class.
The data and functions within a class are called members of the class. Funnily
enough, the members of a class that are data items are called data members and the
members that are functions are called function members or member functions. The
member functions of a class are also sometimes referred to as methods, although we
will not be using this term.

Figure 1.1:

Now let’s keep track of 4 ages instead of just one. We could create 4 separate
variables, but 4 separate variables have limited appeal. (If using 4 separate variables

1
2 Lab 1:Review of CS101 & Arrays (1D and

is appealing to you, then consider keeping track of 93843 ages instead of just 4).
Rather than using 4 separate variables, we’ll use an array.
Here’s how to create an array and one way to initialize an array:
Example 1.2:

1 1: # include <iostream . h>


2
3 2:
4 3 : i n t main ( )
5 4: {
6 5 : short age [ 4 ] ;
7 6 : age [ 0 ] = 2 3 ;
8 7 : age [ 1 ] = 3 4 ;
9 8 : age [ 2 ] = 6 5 ;
10 9 : age [ 3 ] = 7 4 ;
11 1 0 : return 0 ;
12 11: }

On line (5), an array of 4 short’s is created. Values are assigned to each variable in
the array on line (6) through line (9).

Figure 1.2:

Accessing any single short variable, or element, in the array is straightforward.


Simply provide a number in square braces next to the name of the array. The number
identifies which of the 4 elements in the array you want to access.
The program above shows that the first element of an array is accessed with the
number 0 rather than 1. Later in the tutorial, We’ll discuss why 0 is used to indicate
the first element in the array.
Example 1.4:

1 1: # include <iostream . h>


2
3 2:
4 3 : i n t main ( )
5 4: {
6 5 : short age [ 4 ] ;
7 6 : age [ 0 ] = 2 3 ;
8 7 : age [ 1 ] = 3 4 ;
9 8 : age [ 2 ] = 6 5 ;
10 9 : age [ 3 ] = 7 4 ;
11 1 0 : cout <<" Age at index [ 0 ] = " <<age [0] < < endl
12 ; 1 1 : cout <<" Age at index [ 1 ] = " <<age [1] < < endl ;
3

13 1 2 : cout <<" Age at index [ 2 ] = " <<age [2] < < endl
14 ; 1 3 : cout <<" Age at index [ 3 ] = " <<age [3] < <
15 endl ; 1 4 : return 0 ;
16
17 15: }

Lines (10) through line (13) produce the output we are expecting. There is no single
statement in the language that says "print an entire array to the screen". Each element
in the array must be printed to the screen individually.
Copying arrays
Suppose that after filling our 4 element array with values, we need to copy that array
to another array of 4 short’s? Try this:

Example 1.5:

1 1 :# include <iostream . h>


2
3 2:
4 3: i n t main ( )
5 4: {
6 5: short age [ 4 ] ;
7
6: short same_age [ 4 ] ; age [ 0 ] = 2 3 ;
7: age [ 1 ] = 3 4 ; age [ 2 ] = 6 5 ; age [ 3 ] = 7 4 ;
8
8:
9
9:
10
10:
11
11:
12 12:
13 same_age=age ;
14
15 13:
16 1 4 : cout <<" The age cout
at <<"
index
The[age
0 ] "cout
<<same_age
<<" The [age
0 ] cout
; at index [ 1age
<<" The ] " <<same_age
return 0 ; [ 1 ] ; at index [ 2 ] " <<same_age [ 2
17 15: }
18 16:
19
17:
18:
20
19:
21

Line (12) tries to copy the age array into the same_age array. What happened
when you tried to compile the program above?
The point here is that simply assigning one array to another will not copy the
elements of the array. The hard question to answer is why the code doesn’t compile.
Later in the tutorial this example will be re-examined to explain why line (12) doesn’t
work. This code should not compile on either C or C++ compilers. However, some
older C++ compilers may ignore the ISO C++ standard and allow line 12 to compile.
If it does compile on your C++ compiler, make a mental note that it is incorrect
behavior.
Let’s try copying arrays using a technique similar to the technique used to print
arrays (that is, one element at a time):
4 Lab 1:Review of CS101 & Arrays (1D and

Example 1.6:

1 1 :# include <iostream . h>


2
3 2:
4 3 :i n t main ( ) 4 :{
5 :short age [ 4 ] ;
6 :short same_age [ 4 ] ;
7
8 7:
9 8 :age [ 0 ] = 2 3 ;
10
9 :age [ 1 ] = 3 4 ;
1 0 : age [ 2 ] = 6 5 ;
11
1 1 : age [ 3 ] = 7 4 ;
12
13
12:
14
1 3 : same_age [ 0 ] = age [ 0 ] ; 1 4 : same_age [ 1 ] = age [ 1 ] ; 1 5 : same_age [ 2 ] = age [ 2 ] ; 1 6 : same_age [ 3 ] = age [ 3 ] ;
15
16
17
18
19
20
21 17:
22 1 8 : cout <<" The age cout
at <<"
index [ 0 ]cout
The age = " <<same_age
<<" The age [0]
cout< <<<"
endl
The; at index [ 10];= " <<same_age [1] < < endl ; at index [ 2 ] =
age return
23 19: }
24
20:
25
21:
22:
26
23:
27

This technique for copying arrays works fine. Two arrays are created: age and
same_age. Each element of the age array is assigned a value. Then, in order to
copy of the four elements in age into the same_age array, we must do it element by
element.

Figure 1.3: Copy first element

Figure 1.4: Copy second elementt


5

Like printing arrays, there is no single statement in the language that says "copy
an entire array into another array". The array elements must be copied individually.
The technique used to copy one array into another is exactly the same as the
technique used to copy 4 separate variables into 4 other variables. So what is the
advantage to using arrays over separate variables?
One significant advantage of an array over separate variables is the name. In
our examples, using four separate variables requires 4 unique names. The 4 short
variables in our array have the same name, age. The 4 short’s in the array are identical
except for an index number used to access them. This distinction allows us to shorten
our code in a way that would be impossible with 4 variables, each with unique names:
Example 1.7:

1 1 :# include <iostream . h>


2
3 2:
4 3 :i n t main ( ) 4 :{
5 :short age [ 4 ] ;
6
7 :short same_age [ 4 ] ; 7 :i n t i , j ;
8 8 :age [ 0 ] = 2 3 ;
9 9 :age [ 1 ] = 3 4 ;
10
1 0 : age [ 2 ] = 6 5 ;
11
12
13
14 1 1 : age [ 3 ] = 7 4 ;
15 12:
16 1 3 : fo r ( i = 0 ; i < 4 ; i ++) same_age [ i ] = age [ i ] ;
17 14:
18
19 15:
20 1 6 : fo r ( j = 0 ; j < 4 ; j ++)
21 1 7 : cout <<" The age i s = " <<same_age [ j ]<<endl ; 1 8 : return 0 ;
22
19: }
23

Since the only difference between each of the short’s in the arrays is their index, a
loop and a counter can be used to more easily copy all of the elements. The same
technique is used to shorten the code that prints the array to the screen. Even though
arrays give us some convenience when managing many variables of the same type,
there is little difference between an array and variables declared individually. There
is no single statement to copy an array, there is no single statement to print an array.
If we want to perform any action on an array, we must repeatedly perform that
action on each element in the array. section*2-Dimensional (2-D) Arrays So far we
have explored arrays with only one dimension. It is also possible for arrays to have
two or more dimensions. The two-dimensional array is also called a matrix.
Here is a sample program that stores roll number and marks obtained by a stu-
dent side by side in a matrix.
6 Lab 1:Review of CS101 & Arrays (1D and

Example 1.8:

1 # include <iostream . h>


2
3 void main ( )
4
5 {
6
7 i n t stud [ 4 ] [ 2 ] ;
8
9 int i , j ;
10
11
12 fo r ( i = 0 ; i <= 3 ; i ++ )
13
14 {
15
16 cout <<"\n Enter r o l l no . and marks " <<endl ;
17
18 cin >>stud [ i ][ 0 ] > > stud [ i ] [ 1 ] ;
19
20 }
21
22 cout <<" The Roll No. and Marks are : " <<endl <<endl ; cout <<" RollNo .\ t Marks\n" ;
fo r ( i = 0 ; i <= 3 ; i ++ )
23
24 cout <<stud [ i ][ 0 ] < < " \ t " <<stud [ i ][ 1 ] < < endl ;
25
26
27 }

There are two parts to the program,in the first part through a for loop we read in the
values of roll no. and marks, whereas, in second part through another for loop we
print out these values.
Look at the cin( ) statement used in the first for loop:
1 cin >>stud [ i ][ 0 ] > > stud [ i ] [ 1 ] ;

In stud[i][0] and stud[i][1] the first subscript of the variable stud, is row number
which changes for every student. The second subscript tells which of the two columns
are we talking about —he zeroth column which contains the roll no. or the first col-
umn which contains the marks. Remember the counting of rows and columns begin
with zero. The complete array arrangement is shown below.

Table 1.1: Add caption


col no. 0 col no. 1
row no. 0 1234 56
row no. 1 1212 33
row no. 2 1434 80
row no. 3 1312 78
7

Thus, 1234 is stored in stud[0][0], 56 is stored in stud[0][1] and so on. The above
arrangement highlights the fact that a two- dimensional array is nothing but a col-
lection of a number of one-dimensional arrays placed one below the other.
In our sample program the array elements have been stored rowwise and ac-
cessed rowwise. However, you can access the array elements columnwise as well.
Traditionally, the array elements are being stored and accessed rowwise; therefore
we would also stick to the same strategy.

Initializing a 2-Dimensional Array

How do we initialize a two-dimensional array? As simple as this:


int stud[4][2] = { { 1234, 56},{ 1212, 33 }, { 1434, 80}, { 1312, 78 }

};
Or we can write like this also..

int stud[4][2] = { 1234, 56, 1212, 33, 1434, 80, 1312, 78 } ;

The above format work also but it is more difficult to read as compared to the first
one. It is important to remember that while initializing a 2-D array it is necessary
to mention the second (column) dimension, whereas the first dimension (row) is op-
tional.

Thus the declarations,

int arr[2][3] = { 12, 34, 23, 45, 56, 45} ;

int arr[ ][3] = { 12, 34, 23, 45, 56, 45 } ;

are perfectly acceptable, whereas,

int arr[2][ ] = { 12, 34, 23, 45, 56, 45 } ;

int arr[ ][ ] = { 12, 34, 23, 45, 56, 45 } ;


would never work.

Memory Map of a 2-Dimensional Array

Let see the arrangement of the above student arrays in memory which contains roll
number and marks.
8 Lab 1:Review of CS101 & Arrays (1D and

Figure 1.5:

Example 1.9:
This example will simply define an array of 2x3 and take input from user and prints
scanned array.
1 # include <iostream . h>
2
3 void main ( )
4
5 {
6
7 int arr [2][3] , i , j ;
8
9 fo r ( i = 0 ; i < 2 ; i ++)
10
11 fo r ( j = 0 ; j < 3 ; j ++)
12
13 {
14
15 cout <<" Enter Value fo r " << i +1 << " row " << j +1 <<" column\n" ; cin >>ar r [ i ] [ j
];
16
17 }
18
19 cout <<"\n ! ! ! Scanning Array Complete ! ! ! \ n\n\n" ;
20
21 fo r ( i = 0 ; i < 2 ; i ++)
22
23 {
24
25 fo r ( j = 0 ; j < 3 ; j ++)
26 cout <<a r r [ i ] [ j ] <<"\ t " ;
27
28 cout <<"\n\n" ;
29
30 }
31
32 }

Example 1.10:
9

1 # include <iostream >


2
3 using namespace std ;
4
5 i n t main ( )
6
7 {
8
9 // A 2−Dimensional array double dis t anc e [ 2 ] [ 4 ] ; cout <<" Enter values\n " ;
10
11 fo r ( i n t i = 0 ; i < 2 ; ++ i ) // t h i s loop i s fo r Rows
12 fo r ( i n t j = 0 ; j < 4 ; ++ j ) // t h i s loop i s fo r Columns
13 cin >>dis t anc e [ i ] [ j ] ; // ge t t i n g values from the user
14 cout << " Members of the array " ; // the statement w i l l be p r i n t as i t i s
15 fo r ( i n t i = 0 ; i < 2 ; ++ i ) // For Rows
16 fo r ( i n t j = 0 ; j < 4 ; ++ j ) // For Columns
17
18 cout << "\n Distance [ " << i << " ] [ " << j << " ] : " << dis t anc e [ i ] [ j ] ; //
Pr in t in g Rows and Columns
19
20 cout << endl ;
21
22 return 0 ;

Arrays and Functions:


An array can be passed to a function as argument. An array can also be returned by
a function. To declare and define that a function takes an array as argument, declare
the function as you would do for any regular function and, in its parentheses, specify
that the argument is an array. Here is an example:
1 # include <iostream >
2
3 using namespace std ;
4
5 void DisplayTheArray ( double member [ ] ) // function {
6 fo r ( i n t i = 0 ; i < 5 ; ++ i )
7
8 cout << "\n Distance " << i + 1 << " : " << member[ i ] ; cout << endl ;
9 }
10
11 i n t main ( )
12
13 {
14 const i n t numberOfItems = 5 ;
15 double dis t anc e [ ] = { 4 4 . 1 4 , 7 2 0 . 5 2 , 9 6 . 0 8 , 4 6 8 . 7 8 , 6 . 2 8 } ;
16
17
18 cout << " Members of the array " ; DisplayTheArray ( dis t anc e ) ;
19
20
21
22 // c a l l i n g the function
23
1 Lab 1:Review of CS101 & Arrays (1D and

24
25 return 0;
26
27 }

Figure 1.6:

Note:

Before doing your lab exercises run the examples.

Exercise:

Q1. Write a program to find out number of even and odd out of array of size 10.

Figure 1.7:

Q2. Write a program to sort the array of size 10 in ascending order.


1

Figure 1.8:

Q3. Write a program by declaring two functions maximum and minimum. Ini-
tialize two dimensional array of size 3*3 with integer numbers in main function of
the program. Pass array as parameter to function maximum to find out maximum
number and to function minimum to find out minimum number. Display minimum
and maximum numbers from main function of the program.

Figure 1.9:
1 Lab 1:Review of CS101 & Arrays (1D and
Chapter 2

Lab 2 Pointers in C++

In this lab we will be discussing pointers in detail. This is one of the most
important concepts in C++ language. Pointers are used everywhere in C++, so if you
want to use the C++ language fully you have to have a very good understanding of
pointers. They have to become comfortable for you.
C++ uses pointers in three different ways:
â A˘ c´ C++ uses pointers to create dynamic data structures – data structures
built up from blocks of memory allocated from the heap at run-time.
â A˘ c´ C++ uses pointers to handle variable parameters passed to functions.
â A˘ c´ Pointers in C++ provide an alternative way to access information
stored in arrays. Pointer techniques are especially valuable when you work with
strings. There is an intimate link between arrays and pointers in C++.
To fully grasp the concept of pointers all you need is the concept and practice of
pointers. Before talking about pointers letâ A˘ Z´ s talk a bit about computer
memory.

Computer Memory
Essentially, the computer’s memory is made up of bytes. Each byte has a number,
an address, associated with it. The picture below represents several bytes of a com-
puter’s memory. In the picture, addresses 924 thru 940 are shown.

Figure 2.1:

Variable and Computer Memory


A variable in a program is something with a name, the value of which can vary. The
way the compiler handles this is that it assigns a specific block of memory within
the computer to hold the value of that variable. The size of that block depends on
the

13
1 Lab 2 Pointers in

range over which the variable is allowed to vary. For example, on 32 bit PC’s the size
of an integer variable is 4 bytes. On older 16 bit PCs integers were 2 bytes.

Example 2.1:

1 # include <iostream >


2
3 using namespace std ;
4
5 i n t main ( )
6 {
7
8 float fl =3.14
9
10 ; cout << f l ;
11
12 cin >> f l ;
13
14 return 0;
15
16 }

The output for this program will be

Figure 2.2:

How It Works: (Explanation)


At line (4) in the program above, the computer reserves memory for fl. Depending
on the computer’s architecture, a float may require 2, 4, 8 or some other number of
bytes. In our example, we’ll assume that a float requires 4 bytes.

Figure 2.3:

When fl is used in line (5), two distinct steps occur:


1

1. The program finds and grabs the address reserved for fl–in this example 924.
2. The contents stored at that address are retrieved
The illustration that shows 3.14 in the computer’s memory can be misleading.
Looking at the diagram, it appears that "3" is stored in memory location 924, "." is
stored in memory location 925, "1" in 926, and "4" in 927. Keep in mind that the
computer actually converts the floating point number 3.14 into a set of ones and
zeros. Each byte holds 8 ones or zeros. So, our 4 byte float is stored as 32 ones and
zeros (8 per byte times 4 bytes). Regardless of whether the number is 3.14, or -273.15,
the number is always stored in 4 bytes as a series of 32 ones and zeros.

Pointer:

In C++ a pointer is a variable that points to or references a memory location in which


data is stored. A pointer is a variable that points to another variable. This means
that a pointer holds the memory address of another variable. Put another way, the
pointer does not hold a value in the traditional sense; instead, it holds the address
of another variable. A pointer "points to" that other variable by holding a copy of
its address. Because a pointer holds an address rather than a value, it has two parts.
The pointer itself holds the address and that address points to a value.

Pointer declaration:

A pointer is a variable that contains the memory location of another variable. The
syntax is as shown below. You start by specifying the type of data stored in the
loca- tion identified by the pointer. The asterisk tells the compiler that you are
creating a pointer variable. Finally you give the name of the variable.
Data_type *variable_name
Such a variable is called a pointer variable (for reasons which hopefully will become
clearer a little later). In C++ when we define a pointer variable we do so by preceding
its name with an asterisk. In C++ we also give our pointer a type which, in this case,
refers to the type of data stored at the address we will be storing in our pointer. For
example, consider the variable declaration:
int *ptr;
int k;

ptr is the name of our variable (just as k is the name of our integer variable). The
’*’ informs the compiler that we want a pointer variable, i.e. to set aside however
many bytes is required to store an address in memory. The int says that we intend to
use our pointer variable to store the address of an integer.
1 Lab 2 Pointers in

Referencing Operator
Suppose now that we want to store in ptr the address of our integer variable k. To
do this we use the unary & operator and write:
ptr = &k;
What the & operator does is retrieve the address of k, and copies that to the contents
of our pointer ptr. Now, ptr is said to "point to" k.

Dereferencing operator
The "dereferencing operator" is the asterisk and it is used as follows:
*ptr = 7;
will copy 7 to the address pointed to by ptr. Thus if ptr "points to" (contains the
address of) k,the above statement will set the value of k to 7. That is, when we use
the ’*’ this way we are referring to the value of that which ptr is pointing to, not the
value of the pointer itself.
Similarly, we could write:
cout«*ptr«endl;
to print to the screen the integer value stored at the address pointed to by ptr;.

Here is graphical representation of Pointers.

Figure 2.4:

This Example will be very helpful in understanding the pointers. Understand it


thoroughly how it works and then proceed.

Example 2.2:

1 # include <iostream >


2 using namespace std ;
3 i n t main ( )
4 {
1

5 int f i r s t v a l u e = 5 , secondvalue = 1 5 ; i n t ∗ p1 , ∗ p2 ;
6 p1 = &f i r s t v a l u e ; // p1 = address of f i r s t v a l u e
7 p2 = &secondvalue ;// p2 = address of secondvalue
8 ∗p1 = 1 0 ; // value pointed by p1 = 10
9
10
11 ∗p2 = ∗p1 ;// value pointed by p2 = value pointed by p1
12 p1 = p2 ;// p1 = p2 ( value of po inte r i s copied )
13 ∗p1 = 2 0 ; // value pointed by p1 = 20
14 cout <<" F i r s t Value i s " << f i r s t v a l u e <<endl ;
15
16 cout <<" Second Value i s " <<secondvalue <<endl ; return 0 ;
17
18 }
19

Output of this listing is as follows:

Figure 2.5:

Here in this code we are trying to play with memory and address of our vari-
ables for the better understanding of Pointers. On line number 5 we have two integer
variables (i.e firstvalue and secondvalue). Both are assigned values of 5 and 15 re-
spectively. On line number 6 we have two integer pointer variables (i.e p1 and p2).
Both are assigned addresses of variables in line 5 firstvalue and secondvalue
respec- tively in line 7 and 8.

Figure 2.6:

In line 9 we see that *p1 is assigned value 10. This means that 10 should be copied
in the variable, which is lying on an address to which p1 is pointing. We know that
p1 is pointing to address of firstvalue. So line 9 results in assigning firstvalue the
value of 10.
1 Lab 2 Pointers in

Figure 2.7:

In line 10 we encounter another assignment which says that value of variable


pointed by p2 should be replaced with the value of variable pointed by p1. So now
secondvalue is assigned with value 10 as well.

Figure 2.8:

Well the assignment in line 11 is a bit confusing but very simple, all this assign-
ment is doing is that now p1 is pointing to the same address as p2. So now we can
say p1 and p2 are pointing at same address.

Figure 2.9:
1

In line 12 we see that *p1 is assigned value 20. This means that 10 should be
copied in the variable, which is lying on an address to which p1 is pointing. We know
that p1 is now pointing to address of secondvalue because in last line we pointed
p1 to the address being pointed by p2. So line 12 results in assigning secondvalue
the value of 20.

Figure 2.10:

Now when we print the value of first value and second value it prints 10 for
firstvalue and 20 for secondvalue; which is right due to the reasons explained above.

Pointers: Pointing to the Same Address

Here is a cool aspect of C++: Any number of pointers can point to the same address.
For example, you could declare p, q, and r as integer pointers and set all of them to
point to i, as shown here:

1 int i ;
2
3 i n t ∗p , ∗q , ∗ r ;
4
5
6
7 p = &i ;
8
9 q = &i ;
10
11 r= p;

Note that in this code, r points to the same thing that p points to, which is i. You can
assign pointers to one another, and the address is copied from the right-hand side
to the left-hand side during the assignment. After executing the above code, this is
how things would look:
2 Lab 2 Pointers in

Figure 2.11:

The variable i now has four names: i, *p, *q and *r. There is no limit on the
number of pointers that can hold (and therefore point to) the same address.

Pointer Arithmetic’s
Like other variables pointer variables can be used in expressions. For example if p1
and p2 are properly declared and initialized pointers, then the following statements
are valid.
1 y=∗p1 ∗ ∗p2 ;
2 sum=sum+∗p1 ;
3 z= 5 − ∗p2$/$∗p1 ;
4 ∗p2= ∗p2 + 1 0 ;

C++ allows us to add integers to or subtract integers from pointers as well as to


subtract one pointer from the other. We can also use short hand operators with the
pointers p1+ =; sum+ = ∗p2; etc.,
we can also compare pointers by using relational operators the expressions such as
p1 > p2, p1 == p2 and p1! = p2 are allowed.
When an integer is added to, or subtracted from, a pointer, the pointer is not simply
incremented or decremented by that integer, but by that integer times the size of the
object to which the pointer refers. The number of bytes depends on the object’s data
type.
When an integer is added to, or subtracted from, a pointer, the pointer is not simply
incremented or decremented by that integer, but by that integer times the size of the
2

object to which the pointer refers. The number of bytes depends on the object’s data
type.

Program to illustrate the pointer expression and pointer arith-


metic

Example 2.3:

1 : # include <iostream >


2 : using namespace std ;
3
4 :i n t main ( ) 4 :{
5
6 5 : i n t ∗ ptr 1 , ∗ ptr 2 ;
7 6: int a,b,x,y,z;
8
9 7 : a = 30 ; b = 6 ;
10 8 : ptr 1=&a ; 9 : ptr 2=&b ;
11
12
13 1 0 : x=∗ ptr 1 + ∗ ptr 2 − 6 ;
14 1 1 : y=6 − ∗ ptr 1 / ∗ ptr 2 + 30 ;
15
16 1 2 : cout <<" Address of a : " <<ptr 1 <<endl ;
17
18 1 3 : cout <<" Address−Value in ptr 1 : " <<∗ptr 1 <<endl <<endl ; //The comment value
i s the value of ptr 1 ( address of the a )
19
20 1 4 : cout <<" Address of b : " <<ptr 2 <<endl ;
21
22 1 5 : cout <<" Address−Value in ptr 1 : " <<∗ptr 2 <<endl <<endl ; //The comment value
i s the value of ptr 2 ( address of the b )
23
24 1 6 : cout <<" a : " <<a<<" b : " <<b<<endl <<endl ; of a and b
25 //Simply p r i n t s the value
26
27 1 7 : cout <<" x : " <<x<<" y : and y". <<y<<endl <<endl ; //Simply p r i n t s the value of x

28
29 1 8 : ptr 1 =ptr 1 + 1 ; // adds 4 in address of ptr 1 . ( 1 ∗ 4 = 4 )
30 1 9 : ptr 2 = ptr 2 ;
31 2 0 : cout <<" a : " <<a<<" b : " <<b<<endl ; of a and b
32 //Simply p r i n t s the value
33
34 2 1 : cout <<" Value in ptr 1 : " <<ptr 1 <<endl <<endl ; // 2293564 //The comment value i s the new memory l o

35 22:
36 cout <<"\nAddress−Value in ptr 1 : " <<∗ptr 1 <<endl <<endl ; // garbage value
//The comment value i s the new value of ptr 1 ( garbage value )
37
38 23: cout <<" Address of b : " <<ptr 2 <<endl <<endl ;
2 Lab 2 Pointers in

39 2 4 : cout <<"\nAddress−Value in ptr 1 : " <<∗ptr 2 <<endl <<endl ;


40 cin >>a ;
41
42 }

Here note that adding some thing in *ptr1 changes the value of the address stored
in ptr. However adding some thing in ptr will change the address it is pointing to.
Printing ptr1 after adding 1 in it gives different address as it has changed by 4 Bytes.

Figure 2.12:

How it Works:
This code explains all the rules related to arithematic of pointers. From line 1 to
line 11, it is simply adding, subtracting and like manipulating with the pointers and
variables. After all the manipulations and arithmetics it started printing values of
pointers and other simple variables till line 12.

Figure 2.13:

At line 18 it adds 1 to ptr1. Mostly people think that this will change the address
of the pointer, but they are totally wrong. Remember pointer is pointing to an ad-
dress. This addition does not change the address of the pointer, infact it changes the
value of the pointer (not the value of the address pointer is pointing at.). ptr1 has the
address of variable of variable a . So it adds 1 *4 Btytes = 4 bytes in the address of a
2

which is stored in ptr1. Where as ptr2 points at the same value as before due to the
assignment of line 19.

Figure 2.14:

Line 20 prints the same value as was printed by the Line 16, because values
of the variable was never changed, in fact ptr1âA˘ Z´ s value which was address
of a was changed. Now Line 21 will print the value stored in ptr1; which is address
of memory 4 bytes ahead of variable a. Line 22 is trying to print the value at
address, ptr1 is now pointing to, which was never assigned any value.

Sending Pointers as Arguments to Functions


When we pass pointers to some function, the addresses of actual arguments in the
calling function are copied into the arguments of the called function. This means that
using these addresses we would have an access to the actual arguments and hence
we would be able to manipulate them. The following program illustrates this fact.
Try this out:

Example 2.4:

1 # include <iostream >


2
3 void swap ( i n t ∗ , i n t ∗) ;
4
5 using namespace std ;
6
7 i n t main ( )
8
9 {
10
11 i n t a = 10 , b = 20
12
13 ; i n t ∗p , ∗q ;
14
15 p = &a ;
16
17 q = &b ;
18
2 Lab 2 Pointers in

19 swap ( p , q ) ;
20
21 cout <<" a : " <<a<<" b : " <<b<<endl ;
22
23 cin >>a ;
24
25 }
26
27 void swap ( i n t ∗x , i n t ∗y )
28
29 {
30
31 int t = ∗x ;
32
33 ∗x = ∗y ;
34
35 ∗y = t ;
36
37 }

The output of the above program would be:

Figure 2.15:

a = 20 b = 10
Note that this program manages to exchange the values of a and b using their ad-
dresses stored in x and y.
Function Pointers
A function pointer is a variable that stores the address of a function that can later be
called through that function pointer. A useful technique is the ability to have pointers
to functions. Their declaration is easy: write the declaration as it would be for the
function, say

int func(int a, float b);

And simply put brackets around the name and a * in front of it: that declares the
pointer. Because of precedence, if you don’t parenthesize the name, you declare a
function returning a pointer:
/* function returning pointer to int */
int *func(int a, float b); //Wrong
2

/* pointer to function returning int */

int (*func)(int a, float b);

Once you’ve got the pointer, you can assign the address of the right sort of func-
tion just by using its name: like an array, a function name is turned into an address
when it’s used in an expression. You can call the function as:

(*func)(1,2);

Example 2.5

1 # include <iostream >


2 using namespace std ; void func ( i n t ) ;
3
4 i n t main ( ) {
5
6 void ( ∗ fp ) ( i n t ) ;
7 fp = func ;
8 ( ∗ fp ) ( 1 ) ;
9 cout <<endl ; fp ( 2 ) ;
10 system ( "PAUSE" ) ; return 0 ;
11 }
12 Void func ( i n t arg )
13
{
cout <<arg<<endl ;
14
}
15
16
17

Pointers and arrays


The concept of arrays is related to that of pointers. In fact, arrays work very much
like pointers to their first elements, and, actually, an array can always be implic-
itly converted to the pointer of the proper type. For example, consider these two
declarations:
1 i n t myarray [ 2 0 ] ; i n t ∗ mypointer ;
2
3
4

The following assignment operation would be valid: mypointer = myarray; After


that, mypointer and myarray would be equivalent and would have very similar prop-
erties. The main difference being that mypointer can be assigned a different address,
whereas myarray can never be assigned anything, and will always represent the same
block of 20 elements of type int. Therefore, the following assignment would not be
2 Lab 2 Pointers in

valid:
myarray = mypointer;
Let’s see an example that mixes arrays and pointers:

Example 2.6:

1 # include <iostream > using namespace std ; i n t main ( )


2 {
3 i n t numbers [ 5 ] ;
4
5
6
7
8
9 int ∗ p;
10 p = numbers ; ∗p = 1 0 ;
11 p++;∗p = 2 0 ;
12
13 p = &numbers [ 2 ] ;∗p = 3 0 ;
14 p = numbers + 3 ; p = ∗p = 4 0; ;
numbers
15 ∗( p+4 ) = 5 0 ;
16 fo r ( i n t n= 0 ; n< 5 ; n++)
17 cout << numbers [ n ] << " , " ; return 0 ; }
18

Output would be
10, 20, 30, 40, 50, Pointers and arrays support the same set of operations, with the
same meaning for both. The main difference being that pointers can be assigned new
addresses, while arrays cannot.

In the chapter about arrays, brackets ([]) were explained as specifying the index
of an element of the array. Well, in fact these brackets are a dereferencing operator
known as offset operator. They dereference the variable they follow just as * does,
but they also add the number between brackets to the address being dereferenced.
For example:

1 a [ 5 ] = 0 ; // a [ o f f s e t of 5 ] = 0
2
3 ∗( a +5 ) = 0 ; // pointed by ( a +5 ) = 0

These two expressions are equivalent and valid, not only if a is a pointer, but also if
a is an array.

Remember that if an array, its name can be used just like a pointer to its first
element.
2

Note:
Before doing your lab exercises run the examples.

Exercise:
Q1: Write a program to take 10 values from user and store them in an array. Then
use pointers to display the squared values of the array in reverse order.

Q2: Write a program to ask 5 values from user and store them in an array, the
program should find the max value of the array by calling to a function, assign that
max value to variable Max and then display it in main using pointer.

Q3: Write a program that passes two values to a function "greater" through pointer
to function method. Display in main () which number is greater.
2 Lab 2 Pointers in
Chapter 3

Lab 3:Strings in C++

Handling of Character String


A string is a sequence of characters. Any sequence or set of characters defined
within double quotation symbols is a constant string. In C++ it is required to do
some meaningful operations on strings they are:
â A˘ c´ Reading string â A˘ c´ Displaying strings â A˘ c´ Combining or concatenating strings
â A˘ c´ Copying one string to another. â A˘ c´ Comparing string & checking whether they
are equal â A˘ c´ Extraction of a portion of a string Strings are stored in memory as
ASCII codes of characters that make up the string appended with ’ \0 ’ (ASCII value
of null). Normally each character is stored in one byte; successive characters are
stored in successive bytes.

Figure 3.1:

29
3 Lab 3:Strings in

Arrays of Characters

Re-Introduction to Characters

As it happens, strings are the most used items of computers. In fact, anything the
user types is a string. It is up to you to convert it to another, appropriate, type of
your choice. This is because calculations cannot be performed on strings. On the
other hand, strings can be a little complex,which is why we wanted to first know
how to use the other types and feel enough comfortable with them.

Consider a name such as James. This is made of 5 letters, namely J, a, m, e, and


s. Such letters, called characters, can be created and initialized as
follows: char L1 = ’J’, L2 = ’a’, L3 = ’m’, L4 = ’e’, L5 = ’s’;

To display these characters as a group, you can use the following:

cout « "The name is " « L1 « L2 « L3 « L4 « L5;

Here is such a program:

Example 2.3:

1 # include <iostream >


2
3 using namespace std ;
4
5 i n t main ( )
6
7 {
8
9 char L1 = ’ J ’ , L2 = ’ a ’ , L3 = ’m’ , L4 = ’ e ’ , L5 = ’ s ’ ;
10
11 cout << " The name i s " << L1 << L2 << L3 << L4 << L5 ;
12
13 return 0 ;
14
15 }

This would produce:


3

Figure 3.2:

Declaring and Initializing an Array of Characters

When studying arrays, we were listing the numeric members of the array between
curly brackets. Here is an example:

int Number[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Because a character is initialized by including it in single-quotes, when creating an
array of characters, to initialize it, you must also include each letter accordingly. A
name such as James can be initialized as follows:

char Name[6] = { ’J’, ’a’, ’m’, ’e’, ’s’ };

As done with other arrays, each member of this array of characters can be accessed
using its index. Here is an example:

Example 3.1:

1 # include <iostream >


2 using namespace std ;
3
4 i n t main ( )
5
6 {
7 char Name[ 6 ] = { ’ J ’ , ’ a ’ , ’m’ , ’ e ’ , ’ s ’ } ;
8
9 cout << " The name i s " << Name[ 0 ] << Name[ 1 ] << Name[ 2 ] << Name[ 3 ] <<
Name [ 4 ] ;
10
11 return 0;
12 }
3 Lab 3:Strings in

Figure 3.3:

The C/C++ provides another alternative. It allows you to declare and initialize the
array as a whole. To do this, include the name in double-quotes. With this technique,
the curly brackets that delimit an array are not necessary anymore. Here is an
exam- ple:

char Name[12] = "James";

With this technique, the item between the double-quotes is called a string. It is
also referred to as the value of the string or the value of the variable.
When declaring and initializing an array of characters, the compiler does not need to
know the number of characters of the string. In fact, you can let the compiler figure
it out. Therefore, you can leave the square brackets empty:
char Name[] = "James";

After declaring such an array, the compiler would count the number of characters
of the variable, add one more variable to it and allocate enough space for the vari-
able. The character added is called the null-terminated character and it is represented
as \0. Therefore, a string such as James would be stored as follows:

Table 3.1: Add caption


J a m e s \0

Streaming an Array of Characters


Like any other variable, before using a string, you must first declare it, which is done
by type the char keyword, followed by the name of the variable, followed by square
brackets. When declaring the variable, if/since you do not know the number of
characters needed for the string; you must still provide an estimate number. You can
provide a value large enough to accommodate the maximum number of characters
that would be necessary for the variable. For a person’s name, this could be 20. For
the title of a book or a web page, this could be longer. Here are examples:
1 char Name[ 2 0 ] ;
3

2 char Book Title [ 4 0 ] ;


3 char WebReference [ 8 0 ] ;
4
5 char WeekDay [ 4 ] ;

To request the value of an array of characters, use the cin extractor just like you would
proceed with any other variable, without the square bracket. Here is an example:
1 char WeekDay [ 1 2 ] ;
2 cout << " Enter today ’ s name : " ;
3 c in >> WeekDay ;

To display the value of an array of characters, use the cout extractor as we have used
it with all other variables, without the square brackets. Here is an example:

Example 3.2:

1 # include <iostream >


2
3 using namespace std ;
4
5 i n t main ( )
6
7 {
8
9 char WeekDay [ 1 2 ] ;
10
11 char EndMe [ ] = "\n" ;
12
13 cout << " Enter today ’ s name : " ;
14 c in >> WeekDay ;
15
16 cout << " Today i s " << WeekDay ;
17
18 cout << EndMe ;
19
20 return 0;
21
22 }

Here is an example of running the program:

Enter today’s name: Thursday

Multidimensional Arrays of Characters


C/C++ treats arrays of characters differently than it does the other arrays. For
exam- ple, we have learned to declare a two-dimensional array of integers as
follows:

int Number[2][6] ={ { 31, 28, 31, 30, 31, 30 },


3 Lab 3:Strings in

{ 31, 31, 30, 31, 30, 31 } };

This variable is in fact two arrays and each array contains 6 integers. For a string, if
you want to declare a two-dimension array of characters, the first dimension specifies
the number of string in the variable. The second dimension specifies the number of
characters that each string can hold. Here is an example:

char StudentName[4][10] = { "Hermine", "Paul", "Gertrude", "Leon"};

In this case, the StudentName variable is an array of 4 strings and each string can
have a maximum of 9 characters (+1 for the null-terminated character). To locate a
string on this variable, type the name of the array followed by its index, which is
the index of the column. This means that the first string of the StudentName array
can be accessed with StudentName[0]. The second would be StudentName[1], etc.
This allows you to display each string on the cout extractor:

Example 3.3:

1 # include <iostream >


2
3 using namespace std ; i n t main ( )
4
5 { char StudentName [ 4 ] [ 1 0 ] = { " Hermine " , " Paul " , " Gertrude " , " Leon " } ; cout
6 << " Student Names" ;
cout << "\nStudent 1 : " << StudentName [ 0 ] ; cout << "\nStudent 2 : " << StudentName [ 1 ] ;
7
8
9
10 cout << "\nStudent cout3<<
: ""\nStudent
<< StudentName
return [ 02 ;] ; " << StudentName [ 3 ] ;
11 } 4:
12
13

This would produce:

Student Names
Student 1: Hermine
Student 2: Paul
Student 3: Gertrude

Student 4: Leon

When declaring and initializing such an array, the compiler does not need to know
the number of strings in the array; it can figure it out on its own. Therefore, you
can leave the first pair square brackets empty. If you are only declaring the array but
cannot initialize, then you must specify both dimensions.
3

Declaring a Pointer to Characters

Figure 3.4:

Pointers can be quite challenging to learn. The diagram should provide a better in-
sight.
The variable name (a pointer to a char) was located at address 0x007fe78. A
pointer is 32 bits, ie. 4 bytes long and holds an address of the string which was
0x00408004. Addresses are always given in hexadecimal. The arrow shows what
the pointer is pointing to, ie what is at the address in the pointer variable.

At this address there were 13 bytes holding the string "David Bolton" with a ter-
minating NULL, the same value as ’\0’.

Earlier, we declared an array as follows:

char EndMe[] = "";

The name of the variable is a pointer to the beginning of the array. For this rea-
son, the name of the reason is sufficient to locate its value. Since in this case we do
not specify the number of characters in the array, we can also just use a pointer to
the array as the beginning of the array. The array can therefore be declared as follows:

char *EndMe = "";

Once again, to display the value of such an array, simply call its name on the cout
extractor:

1 # include <iostream >


3 Lab 3:Strings in

2 using namespace std ;


3
4
5 i n t main ( )
6
7 {
8 char ∗EndMe = " " ;
9 cout << EndMe ; return 0 ;
10
11
12 }

To request the value of an array of characters from the user, you can declare a pointer
to char and initialize it with an estimate number of characters using the new operator.
Here is an example:

Example 3.4:

1 # include <iostream >


2
3 using namespace std ;
4
5 i n t main ( )
6
7 {
8
9 char ∗StudentName = new char [ 2 0 ] ;
10
11 cout << " Enter Sudent F i r s t Name: " ;
12 c in >> StudentName ;
13 cout << "\nStudent F i r s t Name: " << StudentName ;
14 return 0 ;
15
16 }

Here is an example of running the program:

Enter Sudent First Name: David

Student First Name: David

Arrays of Characters and Pointers

1 # include <iostream >


2 using namespace std ;
3 i n t main ( )
4
5 {
6 double ∗Value ;
7
3

8 Value = 1 2 . 5 5 ;
9 cout << " Value = " << Value ;
10 return 0 ;
11
12 }

On the other hand, the following declaring of an array of characters and its later
initialization is perfectly legal:
Example 3.8:

1 # include <iostream >


2
3 using namespace std ; i n t main ( )
4 {
5
6 char ∗Country ;
7 Country = " Republique d ’ Afrique du Sud" ;
8 cout << " Country Name: " << Country << "\n\n" ; return 0 ;
9
10
11 }

String Manipulation Functions

Strings as Variables

â A˘ c´ To create a variable of type string, simply: string fullName;


â A˘ c´ Assignment, as always is the same: fullName = "Aamir Hassan";

â A˘ c´ Or like before, we could always combine the two with an initialization:


string fullName = "Aamir Hassan";

Input/output with Strings

â A˘ c´ I/O with Strings is as before: string fullName = "";

cout « "Please enter your name: ";

cin » fullName; //get the name

cout « "Your name is " « fullName;


3 Lab 3:Strings in

String Operators: Assignment


â A˘ c´ Assignment (=): As with before, assign a string to a variable of type string.
string oneName = "Edwin";
string anotherName = oneName;
â A˘ c´ Both now hold "Edwin"

String Operators: Concatenation


â A˘ c´ Concatenation (+): Puts a string on the end of another.

string firstName = "Edwin";

string lastName = "Dreese";

string fullName = firstName + "" + lastname;

//the += shorthand also works

string oneString = "2 + 2 = ";

oneString += "5";

Relational String Operators


â A˘ == and != are same as before, but the others are not exactly like usage with

numbers...

â A˘ c´ For instance, what exactly does it mean if one string is "less than" another?

String I/O
â A˘ c´ A common problem with reading strings from user input is that it could
contain white spaces. Remember that white space (e.g. space, tab, newline) is treated
as termination for cin.

â A˘ c´ Take the following code for

example: cout « "Enter your full name: ";

string fullname;
3

//only the first name will be read in!!

cin » fullname;

String Processing

â A˘ c´ In addition to giving us a new data type to hold strings, the string library
offers many useful string processing methods.

â A˘ c´ You can find most of them of them in the book, but here are a few useful

ones. length () and size()

â A˘ c´ This method returns the integer length of the string. The length() and size()
are the same.

â A˘ c´

Example:

string s1 = "Super!";

//the integer 6 will be output.

cout « s1.length() « endl;

at(index)

â A˘ This method returns the character at the specified index. Indices start from

0.

â A˘ c´ Example:

string n = "Vikram";

//the character ’V’ will be output.

cout « n.at(0) « endl;


//the character ’m’ will be output.

cout « n.at(n.size()-1) « endl;


4 Lab 3:Strings in

Shorthand for at (index)


â A˘ c´ As an alternative, we could have also used the following equivalent

shorthand: string n = "Vikram";

//the character ’V’ will be output.

cout « n[0] « endl;

//the character ’m’ will be output.

cout « n[n.size()-1] « endl;

erase(index)
â A˘ c´ This method removes all characters from the string starting from the
specified index to the end.

â A˘ c´ The length of the new string is reset to

index! â A˘ c´ Example:

string os = "Operating Systems";

os.erase(9);

//the string "Operating" is output

cout « os « endl;

//length is now 9, the index

cout « os.length() « endl;

find(str)
â A˘ This method returns the integer index of the first occurrence of the specified

string
4

â A˘ c´ Example:

string d = "data data data";

//0 is output

cout « d.find("data") « endl;

find(str, index)
â A˘ c´ This method returns the integer index of the first occurrence of the specified
string starting from the specified

index. â A˘ c´ Returns -1 if pattern is

not found. â A˘ c´ Example:

string d = "data data data";

//5 is output

cout « d.find("data", 1) « endl;

â A˘ c´ Why? Because by specifying a starting index of 1, we only consider "ata


data data"

insert(index, str)
â A˘ c´ Inserts the specified string at the specified index.

â A˘ c´ Example:

string animal = "Hippo";

animal.insert(0, "Happy ");

//outputs "Happy Hippo"

cout « animal « endl;


4 Lab 3:Strings in

replace(index, n, str)
â A˘ c´ Removes n characters in the string starting from the specified index, and
inserts the specified

string, str, in its

place. â A˘ c´

Example:

string transport = "Speed Boat";

transport.replace(0, 5, "Sail");

//outputs "Sail Boat"

cout « transport « endl;

substr(index, n)
â A˘ c´ Returns the string consisting of n characters starting from the specified
index. â A˘ c´ Example:

string transport = "Cruise Ship";

//outputs "Ship"

cout « transport.substr(7, 4) « endl;

Some String Functions


â A˘ c´

strlen() â A˘ c´

strcpy() â A˘ c

´ strncpy()

â A˘ c´

strcat() â A˘ c´

strncat()
4

â A˘ c´

strcmp() â A˘ c´

strncmp()

Strlen ()
Syntax:

len = strlen(ptr);

where len is an integer and ptr is a pointer to char

strlen() returns the length of a string, excluding the null. The following code will
result in len having the value 13.

int len;
char str[15];

strcpy(str, "Hello, world!");

len = strlen(str);

Example 3.9:

1 # include <iostream >


2
3 # include <c s t r i n g >
4
5 using namespace std ;
6
7 i n t main ( )
8
9 {
10 i n t len ;
11
12 char s t r [ 1 5 ] ;
13
14 s t rcpy ( s t r , " Hello , world ! " ) ;
15
16 len = s t r l e n ( s t r ) ;
17
18 cout <<len <<endl ;
19
20 system ( "PAUSE" ) ;
21
4 Lab 3:Strings in

22 return 0;
23
24 }

Strcpy ()
strcpy(ptr1, ptr2);
where ptr1 and ptr2 are pointers to char

strcpy() is used to copy a null-terminated string into a variable. Given the following
declarations, several things are possible.

char S[25];

char D[25];

â A˘ c´ Putting text into a string:

â A˘ c´ strcpy(S, "This is String 1.");


â A˘ c´ Copying a whole string from S to D:
â A˘ c´ strcpy(D, S);
â A˘ c´ Copying the tail end of string S to D:

â A˘ c´ strcpy(D, &S[8]);

N.B. If you fail to ensure that the source string is null-terminated, very strange and
sometimes very ugly things may result.

Strncpy ()
strncpy(ptr1, ptr2, n);
where n is an integer and ptr1 and ptr2 are pointers to char

strncpy() is used to copy a portion of a possibly null-terminated string into a variable.


Care must be taken because the ’\0’ is put at the end of destination string only if it is
within the part of the string being copied. Given the following declarations, several
things are possible.

char S[25];
char D[25];

Assume that the following statement has been executed before each of the remaining
4

code fragments.

â A˘ c´ Putting text into the source


string: â A˘ c´ strcpy(S, "This is String
1.");

â A˘ c´ Copying four characters from the beginning of S to D and placing a null at


the end:
â A˘ c´ strncpy(D, S,
4); â A˘ c´ D[4] = ’\0’;
â A˘ c´ Copying two characters from the middle of string S to
D: â A˘ c´ strncpy(D, &S[5], 2);

â A˘ c´ D[2] = ’\0’;
â A˘ c´ Copying the tail end of string S to D:
â A˘ c´ strncpy(D, &S[8], 15);

Which produces the same result as strcpy(D, &S[8]);

Strcat ()

strcat(ptr1, ptr2);
where ptr1 and ptr2 are pointers to char

strcat() is used to concatenate a null-terminated string to end of another string vari-


able. This is equivalent to pasting one string onto the end of another, overwriting the
null terminator. There is only one common use for strcat().

Char S[25] = "world!";

Char D[25] = "Hello, ";

â A˘ c´ Concatenating the whole string S onto D:

â A˘ c´ strcat(D, S);

N.B. If you fail to ensure that the source string is null-terminated, very strange and
sometimes very ugly things may result.
4 Lab 3:Strings in

Strncat ()
Syntax: strncat(ptr1, ptr2, n);
where n is an integer and ptr1 and ptr2 are pointers to char

strncat() is used to concatenate a portion of a possibly null-terminated string onto


the end of another string variable. Care must be taken because some earlier imple-
mentations of C do not append the ’\0’ at the end of destination string. Given the
following declarations, several things are possible, but only one is commonly used.

Char S[25] = "world!";


Char D[25] = "Hello, ";

â A˘ c´ Concatenating five characters from the beginning of S onto the end of D


and placing a null at the end:
â A˘ c´ strncat(D, S, 5);

â A˘ c´ strncat(D, S, strlen(S) -1);

Both would result in D containing "Hello, world".

N.B. If you fail to ensure that the source string is null-terminated, very strange and
sometimes very ugly things may result.

Strcmp ()
Syntax: diff = strcmp(ptr1, ptr2);
where diff is an integer and
ptr1 and ptr2 are pointers to char

strcmp() is used to compare two strings. The strings are compared character by
character starting at the characters pointed at by the two pointers. If the strings are
identical, the integer value zero (0) is returned. As soon as a difference is found,
the comparison is halted and if the ASCII value at the point of difference in the first
string is less than that in the second (e.g. ’a’ 0x61 vs. ’e’ 0x65) a negative value is
returned; otherwise, a positive value is returned. Examine the following examples.

char s1[25] = "pat";


char s2[25] = "pet";

diff will have a negative value after the following statement is executed.
4

diff = strcmp(s1, s2);

diff will have a positive value after the following statement is

executed. diff = strcmp(s2, s1);

diff will have a value of zero (0) after the execution of the following statement, which
compares s1 with itself.

diff = strcmp(s1, s1);

Strncmp ()

Syntax: diff = strncmp(ptr1, ptr2, n);


where diff and n are integers
ptr1 and ptr2 are pointers to char

strncmp() is used to compare the first n characters of two strings. The strings are
compared character by character starting at the characters pointed at by the two
pointers. If the first n strings are identical, the integer value zero (0) is returned. As
soon as a difference is found, the comparison is halted and if the ASCII value at the
point of difference in the first string is less than that in the second (e.g. ’a’ 0x61 vs. ’e’
0x65) a negative value is returned; otherwise, a positive value is returned. Examine
the following examples.

char s1[25] = "pat";


char s2[25] = "pet";

diff will have a negative value after the following statement is executed.

diff = strncmp(s1, s2, 2);

diff will have a positive value after the following statement is executed.

diff = strncmp(s2, s1, 3);

diff will have a value of zero (0) after the following statement.

diff = strncmp(s1, s2, 1);


4 Lab 3:Strings in

Note:
Before doing your lab exercises run the examples.

Exercise:
Q1: Write a program to count the number of words and number of spaces in a string.

Q2: Write a program to ask the user for a string and then checks where it is a
palindrome or not.
Chapter 4

Lab 4:Structures I

ïCˇ Ÿ Structure Declaration


ïCˇ Ÿ Structure
Definition ïCˇ Ÿ
Structure Variables
ïCˇ Ÿ Structure Membership
ïCˇ Ÿ Arrays of structures

STRUCTURES
Arrays require that all elements be of the same data type. Many times it is neces-
sary to group information of different data types. An example is a materials list for a
product. The list typically includes a name for each item, a part number, dimensions,
weight, and cost.

C and C++ support data structures that can store combinations of character, inte-
ger floating point and enumerated type data. They are called a STRUCTS.

Often multiple variables must be passed from one function to another, and often
these variables have different data types. Thus it is useful to have a container to store
various types of variables in. Structs allow the programmer to do just that

A struct is a derived data type that consists of members that are each fundamen-
tal or derived data types.

struct is used to declare a new data-type. Basically this means grouping variables
together.

Structures Definition
Before a structure is created, it is necessary to define its overall composition. The
format of the a structure is provided in the shape of a template or pattern which is

49
5 Lab

then used to creatstructure variables of the same composition. The template is com-
posed of the names and attributes of the data items to be included in the structure.
The definition begins with the keyword structwhich is followed by a structure decla-
ration consist of a set of user-defined data names and data types. These entries are
separated by semicolons and enclosed within a pair of curly brackets. The definition
ends with a semicolon. Thus, in general, the structure definition has the form

1 s t r u c t tag−name {
2 type var −1;
3
. . . . . . . . . .−2;
type−var ...
4
5 typevar−n ;
6 };

wheretag-name is the user-supplied name that identified the structure template;


type refers to any valid data type such as char, int, float, and so forth; and var-1, var-
2,. ,var-n are user-defined variables names, arrays or pointers. The components of
a structure are commonly referred to as members or field.

Example 4.1:

1 s t r u c t employee
2
3 {
4 char name [ 3 0 ] ;
5 i n t age ;
6 float salary ;
7 }

Representation in Memory

1 s t r u c t student
2 {
3 char name [ 2 0 ] ;
4 introll_no ;
5 };
6 s t r u c t student s t ;

Structures Variables
This code fragment illustrates how structure variables of the type structemployee are
defined.
1 s t r u c t employee {
2 char name [ 3 0 ] ;
3
4 i n t age ;
5 float salary ;
5

Table 4.1:
...

0123 19
roll_no

6 };
7 structemployee emp1 , emp2 , emp3 ;

In the above example three structure variables emp1, emp2, and emp3 are created.
Each structure consists of three members identified by name, age, and salary.
OR
1 s t r u c t employee
2 { char name [ 3 0 ] ;
3
4 i n t age ;
5 float salary ;
6
7 } emp1 , emp2 , emp3 ;

Structure membership
Members themselves are not variables they should be linked to structure variables in
order to make them meaningful members.
The link between a member and a variable is established using the member operator
’.’ i.e. dot operator or period operator. We access individual members of a structure
with the .operator. For example to assign a value, we can enter:
1 structx
2 { int a;
3 int b;
4 int c;
5
6 };
7
8 main ( )
9 {
10 struct x z;
11

12 z . a = 1 0 ; // a s s i g n s member â A˘ Ÿ aâ A˘ Z´ o f s t r u c t u r e v a r i a b l e z
13 value 1 0 . z . b = 2 0 ;
14 z.c = 30;
15
16 }

And to retrieve a value from a structure member://


5 Lab

1
2 struct x
3 {
4 int a;
5 int b;
6 int c;
7 };
8
9 main ( )
10 { struct x z;
11
12 z . a = 1 0 ; // Assigning a value to a member through a s t r u c t u r e va r i a b l e z .
a
++; // incrementing the member va r i a b l e . cout <<z . a ; // Retr ieving the
13 value .
}

Example 4.2:

1 s t r u c t l i b _b o o k s
2 {
3 char t i t l e [ 2 0 ] ;
4 char author [ 1 5 ] ;
5 i n t pages ;
6 f l o a t pr i c e ;
7
8 } book1 , book2 , book3 ;

Now
Book1.price

is the variable representing the price of book1 and can be treated like any other
ordinary variable. We can use scanf statement to assign values like

cin»book1.pages;

Or we can assign variables to the members of book1

strcpy(book1.title,"basic");
strcpy(book1.author,"alagurusamy");
book1.pages=250;
book1.price=28.50;
5

Accessing Structure Variables example:

Example 4.1:

1
2 i n t main ( )
3 {
4
5 s t r u c t Library
6 {
7 i n t ISBN , copies , PYear ;
8 char bookName [ 3 0 ] , AuthorName [ 3 0 ] , PublisherName [ 3 0 ] ;
9
10 };
11
12 Library l i b r a r y Va r i a b l e ;
13 L i br ar y V a r i a b l e . ISBN = 1 2 9 3 ;
14 s t rcpy ( l i b r a r y Va r i a b l e . bookName , " Network S e c ur i t y
15 " ) ; s t rcpy ( l i b r a r y Va r i a b l e . AuthorName , " Martin " ) ;
16
17 s t rcpy ( l i b r a r y Va r i a b l e . PublisherName , " Waley "
18 ) ; l i b r a r y Va r i a b l e . copies = 4 ;
19 l i b r a r y Va r i a b l e . PYear = 1 9 9 8 ;
20 cout <<" ISBN Number : " << l i b r a r y Va r i a b l e . ISBN<<endl ; cout <<" Library book
Name
: " << l i b r a r y Va r i a b l e . bookName<<endl ; cout <<" Author : " << l i b r a r y Va r i a b l
e . AuthorName<<endl ; cout <<" Publisher : " << l i b r a r y Va r i a b l e .
PublisherName ; cout <<"No. of Copies : " << l i b r a r y Va r i a b l e . copies ; cout <<"
21 Year : " <<
22 l i b r a r y Va r i a b l e . PYear ;

Creating multiple structure variables.

1
2 void main ( void )
3 {
4 s t r u c t Library
5 {
6 i n t ISBN , copies , PYear ;
7 char bookName [ 3 0 ] , AuthorName [ 3 0 ] , PublisherName [ 3 0 ] ;
8 };
9
10 Library l i b r a r y Va r i a b l e 1 , l i b r a r y Va r i a b l e 2 , l i b r a r y Va r i a b l e 3 ,
l i b r a r y Va r i a b l e 4 ; Library Library Array [ 4 ] ; // a l t e r n a t i v e and e a s i
e s t way
11
12 }
5 Lab

Assignment a structure variable to another Structure Variable


The value of a structure variable can be assigned to another structure variable of the
same type, e.g:

1
2
3 Library l i b r a r y Va r i a b l e 1 , l i b r a r y Va r i a b l e 2 ;
4 s t rcpy ( l i b r a r y Va r i a b l e 1 . bookName , "C Programming "
5 ) ; l i b r a r y Va r i a b l e 1 . ISBN = 1 2 9 3 ;
6 l i b r a r y Va r i a b l e 2 = l i b r a r y Va r i a b l e 1 ;

STRUCTURE WITHIN A STRUCTURE/ NESTED STRUCTURES


Structures can be implemented with functions and arrays. Moreover, structures can
be implemented as the member of other structure. This is termed as structure within
structure.

When a structure is decleared as the member of another structue, it is called Struc-


ture within a structure. It is also known as nested structure.

Accessing Structure in Structure

1
2 cout <<un i ve r s i t y Va r i a b l e . l i b r a r y Va r i a b l e .
3 bookName ; cout <<un i ve r s i t y Va r i a b l e . c i t y ;
4 cout <<un i ve r s i t y Va r i a b l e . l i b r a r y Va r i a b l e . bookName)
5 ; cout <<un i ve r s i t y Va r i a b l e . l i b r a r y Va r i a b l e . ISBN ) ;

Common Errors in Accessing Structures

1 struct x
2 {
3
4 int a;
5 int b;
6 int c;
7
8 };
9
10 main ( )
11
12 {
13 struct x
14 z;z.a = 10;
15
5

16 z . a ++;
17 cout <<" f i r s t member i s " << a ; // Error !
18
19 // a i s not a va r i a b l e . I t i s only the name of a member in a s t r u c t u r e
cout
20 << â A˘ I˙ f i r s t member i s "<<x . a ; // E r r o r !
21 // x i s not the name of a va r i a b l e . I t i s the name of a type
22
}
Arrays of structures
It is possible to define a array of structures for example if we are maintaining in-
formation of all the students in the college and if 100 students are studying in the
college. We need to use an array than single variables. We can define an array of
structures as shown in the following example:
1 s t r u c t u r e information
2 {
3 intid_no ;
4 char name [ 2 0 ] ;
5 char address [ 2 0 ] ;
6 char combination [ 3 ] ;
7 i n t age ;
8 }
9
10 student [ 1 0 0 ] ;

An array of structures can be assigned initial values just as any other array can. Re-
member that each element is a structure that must be assigned corresponding initial
values as illustrated below.

1
2 i n t main ( void )
3
4 { s t r u c t info
5
6 {
7
8 intid_no ;
9
10 char name [ 2 0 ] ;
11
12 char address [ 2 0 ] ;
13
14 i n t age ;
15
16 } std [ 1 0 0 ] ;
17
18
19 intI ,n;
20
21 cout <<" Enter the number of students " <<endl ;
22 cin >>n ;
5 Lab

23
24 cout <<endl <<" Enter Id_no , name address combination agem" <<endl ; fo r ( I = 0 ; I <n
; I ++)
25
26 {
27
28 cout <<endl <<"\ t Ent e r Record fo r student " <<I +1<<endl ;
29
30 cout <<" Student ID : " <<endl ;
31
32 cin >>std [ I ] . id_no ;
33
34 cout <<" Student Name: " <<endl ;
35
36 cin >>std [ I ] . name ;
37
38 cout <<" Student c i t y : " <<endl ;
39
40 cin >>std [ I ] . address ;
41
42 cout <<" Student Age : " <<endl ;
43
44 cin >>std [ I ] . age ;
45
46 }
47
48 cout <<endl <<" Student information " <<endl ;
49
50 fo r ( I = 0 ; I <n ; I ++)
51
52 { cout <<endl <<" Student ID:\ n\ t " <<std [ I ] . id_no <<endl ; cout <<" Student Name: "
<<std [ I ] . name<<endl ; cout <<" Student c i t y : " <<std [ I ] . address <<endl ; cout
<<" Student Age : " <<std [ I ] . age ;
53
54 }
55
56 }

Note:
Before doing your lab exercises run the examples.

Exercise:
Q1: Write a program using structure to display the area and parameters of Rectangle.
The parameters should be taken form user at run time. The length should be in int
5

and width in float.

Q2: Write a program using structure to display the record of 10 students where
member variable should be Name, roll.no, GPA, semester and age and each of these
members should be input by user at run time. Finally the GPA of all students is
summed up and average GPA should be displayed.
5 Lab
Chapter 5

Lab 5:Structures II

ïCˇ Ÿ Structures and


functions ïCˇ Ÿ Pointers
to Structure ïCˇ Ÿ
Enumerations
ïCˇ Ÿ Bitwise Operations

Structures and functions


A structure can be passed as a function argument just like any other variable. This
raises a few practical issues.
Where we wish to modify the value of members of the structure, we must pass a
pointer to that structure. This is just like passing a pointer to an int type argument
whose value we wish to change. If we are only interested in one member of a struc-
ture, it is probably simpler to just pass that member. This will make for a simpler
function, which is easier to re-use. Of course if we wish to change the value of that
member, we should pass a pointer to it.

When a structure is passed as an argument, each member of the structure is copied.


This can prove expensive where structures are large or functions are called frequently.
Passing and working with pointers to large structures may be more efficient in such
cases

Example 5.1:

1 //Pass ’ s t r u c t ’ elements to a function .


2
3 i n t main ( )
4 {
5 s t r u c t { char name [ 2 0 ]
6 ; i n t age ;
7 } record ;
8
9 s t rcpy ( record . name , " Joe Brown" ) ;

59
6 Lab 5:Structures

10 record . age = 2 1 ;
11 display ( record . name , record . age ) ; return 0 ;
12 }
13
14
15
16 void display ( char ∗name , i n t age )
17 {
18 cout <<"Name i s " <<name <<"\nAge i s " <<age ;
19 }

Example 5.2:

1 // Purpose : Passing a copy of a s t r u c t u r e to a f unc tion .


2
3 # include <iostream >
4 s t r u c t record_format { char name [ 2 0 ] ; i n t age ; } ; void display ( s t r u c t record_format ) ;
5 using namespace std ;
6
7 i n t main ( )
8 {
9 s t r u c t record_format record ;
10
s t rcpy ( record . name , " Joe Brown" ) ; record . age = 2 1 ;
11
12
display ( record ) ;
13
cout <<" name i s " <<record . name<<"\nAge i s " <<record . age ; return 0;
}
14
15
16
void display ( s t r u c t record_format rec ) { cout <<" name i s " <<rec . name<<"\nAge i s " <<rec . age ;
17
18
19
20

21
22
23 rec . age = 31 ;
24
25
26 /∗ change the value of a s t r u c t u r e
27 ∗ member .
28
29
30
31 ∗/
32
33
}
34

Pointers to Structure
As we have learnt a memory location can be accessed by a pointer variable. In
the similar way a structure is also accessed by its pointer. The syntax for structure
6

pointer is same as for the ordinary pointer variable. In general, the structure pointer
is defined by the statement struct-type *sptr; where struct-type refers to structure
type specifier, and sptr ia a variable that points to the structure. It must be ensured
that the pointer definition must preceed the structure declaration. For example, a
pointer to struct employee may be defined by the statement struct employee *sptr; In
other words the variable sptr can hold the address value for a structure of type struct
employee. We can create several pointers using a single declaration, as follows:
] Struct employee *sptr1, *sptr2, *sptr3;
1 We have a s t r u c t u r e :
2
3 s t r u c t employee {
4 char name [ 3 0 ] ;
5 i n t age ;
6 float salary ;
7
8 };

We define its pointer and variable as follow:

struct employee *sptr1, emp1;


A pointer to a structure must be initialized before it can be used anywhere in pro-
gram. The address of a structure variable can be obtained by applying the address
operator & to the variable. For example, the statement sptr1 = &emp1;

Accessing Structure Members Using Arrow Operator


The members of a structure can be accessed using an arrow operator. The arrow
operator-> (consisting of minus sign (-) followed by the greater than (>) symbol). Us-
ing the arrow operator a structure member can be accessed by the expression sptr1-
>member-name Where sptr holds the address of a structure variable, and member-
name is the name of a member belonging to the structure. For example, the values
held by the members belonging to the structure emp1 are given by the expression:

sptr1->name;
sptr1->age;

sptr1->salary;

Using the pointers the members of the structure variable emp1 can be initialized
asfollow:

1 cout <<"\nEnter Name: " ; gets ( sptr 1 −>name) ;


2
6 Lab 5:Structures

3 cout <<"\nEnter age : " ; cin >>sptr 1 −>age ;


4 cout <<"\nEnter Salary : " ;
5
6
7
8 cin >>sptr 1 −>s a l a r y ;
9 // Pr in t in g St r uc t ur e f i e l d s
10 cout <<"\nYou have entered :\ n" ;
11 cout <<sptr 1 −>name<<endl ;
12 cout <<"\ t " <<sptr 1 −>age<<endl ;
13 cout <<"\ t " <<sptr 1 −>salary <<endl ;

Enumerations
An enumeration provides context to describe a range of values. The following exam-
ple shows an enumeration that contains the four suits in a deck of cards.

enum Suit { Diamonds, Hearts, Clubs, Spades };

Every name of the enumeration becomes an enumerator and is assigned a value


that corresponds to its place in the order of the values in the enumeration. By de-
fault, the first value is assigned 0, the next one is assigned 1, and so on. You can set
the value of an enumerator.

enum Suit { Diamonds = 1,


Hearts,
Clubs,

Spades };

The enumerator Diamonds is assigned the value 1. This affects the values that are
assigned to subsequent enumerators; Hearts is assigned the value 2, Clubs is 3, and
so on.

Example 5.3:

1 # include <iostream >


2
3 # include <conio . h>
4
5 using namespace std ;
6
7
8 i n t main ( )
9
6

10 {
11
12 enum Days { Monday=13 , Tuesday =8 , Wednesday , Thursday } ;
13
14 Days d1=Wednesday ;
15
16 cout <<d1 ;
17
18 cout <<endl ;
19
20 int x;
21
22 x= i n t ( d1 +1 ) ;
23
24 cout <<x ;
25
26 getch ( ) ;
27
28 return 0;
29
30 }

Bitwise Operations

Bitwise Complement:
The bitwise complement operator, the tilde, , flips every bit. The tilde is

sometimes called a twiddle, and the bitwise complement twiddles every bit: This
turns out to be a great way of finding the largest possible value for an unsigned
number.

unsigned int max = 0;

Bitwise AND:
The bitwise AND operator is a single ampersand: &:

01001000 &
10111000 =
—————-
00001000
Bitwise OR: The bitwise OR operator is a |:

01001000 |
10111000 =
6 Lab 5:Structures

Table 5.1: Add caption

complement Bit n of x is the opposite of bit n of x

& Bitwise And Bit n of x&y is 1 if bit n of x and bit n of y is 1.

| Bitwise Or Bit n of x|y is 1 if bit n of x or bit n of y is 1.

ˆ Bitwise Exclusive Or Bit n of xyˆ is 1 if bit n of x or bit n of y is 1 but not if both are 1.

» Right Shift (divide by 2) Bit n of x»s is bit n-s of x.

« Left Shift (multiply by 2) Bit n of x«s is bit n+s of x.


6

—————–
11111000

Bitwise Exclusive OR (XOR): The exclusive-or operation takes two inputs and re-
turns a 1 if either one or the other of the inputs is a 1, but not if both are. That
is, if both inputs are 1 or both inputs are 0, it returns 0. Bitwise exclusive-or, with
the operator of a carrot, ^, performs the exclusive-or operation on each pair of bits.
Exclusive-or is commonly abbreviated XOR.

01110010 ^

10101010
————–
11011000

Suppose, we have some bit, either 1 or 0, that we’ll call Z. When we take Z XOR
0, then we always get Z back: if Z is 1, we get 1, and if Z is 0, we get 0. On the other
hand, when we take Z XOR 1, we flip Z. If Z is 0, we get 1; if Z is 1, we get 0:

• myBits ^ 0 : No change
• myBits ^1 : Flip

Example 5.4:

1 # include <iostream >


2 # include <iomanip>
3 using namespace std ;
4
5 void binary ( unsigned i n t u)
6 {
7 i n t upper ;
8 i f ( u < 256 )
9 upper = 1 2 8 ;
10
11 else
12 upper = 32768 ;
13
14 cout << setw ( 5 ) << u << " : " ;
15
16 // check i f b i t i s s e t s t a r t i n g from the highest b i t
17 // ( ex ) upper = 128 , 10000000 , 01000000 , 00100000 , . . . , 00000001
18
19 fo r ( i n t i = upper ; i > 0 ; i = i /2 )
20 {if (u &i)
21 cout << " 1 " ;
22 else
6 Lab 5:Structures

23 cout << " 0 " ;


24 }
25 cout << "\n" ;
26 }
27
28 i n t main ( )
29
30 {
31
32 binary ( 5 ) ;
33
34 binary ( 5 5 ) ;
35
36 binary ( 2 5 5 ) ;
37
38 binary ( 4 5 5 5 )
39
40 ;
41
42 binary ( 1 4 5 5 5 ) ;
43
44 system ( "PAUSE" ) ;
45
46 return 0 ;

Example 5.5:

1
2 # include <iostream >
3
4 # include <iomanip>
5
6 # include < b i t s e t >
7
8 using namespace std ;
9
10 void binary ( unsigned i n t u)
11
12 {
13
14 cout << setw ( 5 ) << u << " : " ;
15
16 cout << b i t s e t <16 >(( i n t ) u) ;
17
18 cout << "\n" ;
19
20 }
21
22 i n t main ( )
23
24 {
25
26 binary ( 5 ) ;
27
6

28 binary ( 5 5 ) ;
29
30 binary ( 2 5 5 ) ;
31
32 binary ( 4 5 5 5 ) ;
33
34 binary ( 1 4 5 5 5 ) ;
35
36 system ( "PAUSE" ) ;
37
38 return 0 ;
39
40 }

Note:
Before doing your lab exercises run the examples.

Exercise:
Q1: Write a program to create a structure of student and ask the user to enter student
name, roll no and marks of three subjects and find the average marks of these three
subjects using a function.

Q2: Write a program for structure of Employee and display the name of employee
and calculate the monthly salary of a specific month. Per day working hours and
salary of employee per hour is entered by the user. Display the name and monthly
salary of employee using pointer to structure.
6 Lab 5:Structures
Chapter 6

Lab 6:Object Orientation in C++ I

Data Types, Objects, Classes and Instances


So far, we’ve learnt that C++ lets you create variables which can be any of a range
of basic data types: int, long, double and so on. However, the variables of the basic
types don’t allow you to model real-world objects (or even imaginary objects) ade-
quately. It’s hard to model a box in terms of an int, for example; what we need is
something that allows us to collect together the various attributes of an object. In
C++, we can do this very easily using classes.

You could define variables, length, breadth and height to represent the dimensions
of the box and bind them together as members of a Box class, as follows:

1 class Box
2 {
3 public :
4 double length ;
5 double breadth ;
6 double height ;
7 };

This code actually creates a new type, called Box. The keyword class defines Box
as such, and the elements that make up this class are defined within the curly braces.
Note that each line defining an element of the class is terminated by a semicolon, and
that a semicolon also appears after the closing brace. The elements length, breadth
and height are referred to as data members. At the top of the class definition, you can
see we have put the keyword public - this just means that the data members are gen-
erally accessible from outside the class. You may, however, place restrictions on the
accessibility of class members, and we’ll see how this works a bit later in this chapter.

With this definition of a new data type called Box, you can go ahead and define
variables of this type just as you did with variables of the basic types:

Box myBox; //Declare a variable myBox of type Box

69
7 Lab 6:Object Orientation in C+

Once we’ve defined the class Box, the declaration of variables of this type is quite
standard. The variable myBox here is also referred to as an object or an instance of
the class Box.

With this definition of a new data type called Box, you can go ahead and define
variables of this type just as you did with variables of the basic types. You can then
create, manipulate and destroy as many Box objects as you need to in your program.
This means that you can model objects using classes and write your programs around
them. So - that’s object-oriented programming all wrapped up then?

Well, not quite. You see, object-oriented programming (OOP) is based on a number
of foundations (famously encapsulation, polymorphism and inheritance) and what
we have seen so far doesn’t quite fit the bill. Don’t worry about what these terms
mean for the moment - we’ll be exploring these ideas in more detail as we learn more
about what you can do with classes.

First Class
The notion of class was invented by an Englishman to keep the general population
happy. It derives from the theory that people who knew their place and function
in society would be much more secure and comfortable in life than those who did
not. The famous Dane, Bjarne Stroustrup, who invented C++, undoubtedly acquired
a deep knowledge of class concepts while at Cambridge University in England, and
appropriated the idea very successfully for use in his new language.

The idea of a class in C++ is similar to the English concept, in that each class usually
has a very precise role and a permitted set of actions. However, it differs from the
English idea, because class in C++ has largely socialist overtones, concentrating on
the importance of working classes. Indeed, in some ways it is the reverse of the En-
glish ideal, because, as we shall see, working classes in C++ often live on the backs
of classes that do nothing at all.

Operations on Classes
In C++ you can create new data types as classes to represent whatever kinds of ob-
jects you like. As you’ll come to see, classes aren’t limited to just holding data; you
can also define member functions that act on your objects, or even operations that act
between objects of your classes using the standard C++ operators. You can define the
class Box, for example, so that the following statements work and have the meanings
7

you want them to have:

1 Box Box1 ;
2 Box Box2 ;
3 i f ( Box1 > Box2 ) // F i l l the l a r ge r box
4 Box1 . F i l l ( ) ;
5 else
6 Box2 . F i l l ( ) ;

You could also implement operations as part of the Box class for adding, subtracting
or even multiplying boxes - in fact, almost any operation to which you could ascribe
a sensible meaning in the context of boxes.

We’re talking about incredibly powerful medicine here and it constitutes a major
change in the approach that we can take to programming. Instead of breaking down
a problem in terms of what are essentially computer-related data types (integer num-
bers, floating point numbers and so on) and then writing a program, we’re going
to be programming in terms of problem-related data types, in other words classes.
These classes might be named Employee, or Cowboy, or Cheese or Chutney, each
defined specifically for the kind of problem that you want to solve, complete with
the functions and operators that are necessary to manipulate instances of your new
types.

Program design now starts with deciding what new application-specific data types
you need to solve the problem in hand and writing the program in terms of opera-
tions on the specifics that the problem is concerned with, be it Coffins or Cowpokes.

Terminology
Let’s summarize some of the terminology that we will be using when discussing
classes in C++:
• A class is a user-defined data type
• Object-oriented programming is the programming style based on the idea of
defining your own data types as classes
• Declaring an object of a class is sometimes referred to as instantiation because
you are creating an instance of a class
• Instances of a class are referred to as objects
• The idea of an object containing the data implicit in its definition, together with
the functions that operate on that data, is referred to as encapsulation
When we get into the detail of object-oriented programming, it may seem a little
complicated in places, but getting back to the basics of what you’re doing can often
help to make things clearer, so always keep in mind what objects are really about.
7 Lab 6:Object Orientation in C+

They are about writing programs in terms of the objects that are specific to the do-
main of your problem. All the facilities around classes in C++ are there to make this
as comprehensive and flexible as possible. Let’s get down to the business of under-
standing classes.

Understanding Classes
A class is a data type that you define. It can contain data elements, which can either
be variables of the basic types in C++ or other user-defined types. The data
elements of a class may be single data elements, arrays, pointers, arrays of pointers
of almost any kind or objects of other classes, so you have a lot of flexibility in what
you can include in your data type. A class can also contain functions which operate
on objects of the class by accessing the data elements that they include. So, a class
combines both the definition of the elementary data that makes up an object and
the means of manipulating the data belonging to individual instances of the class.

The data and functions within a class are called members of the class. Funnily
enough, the members of a class that are data items are called data members and the
members that are functions are called function members or member functions. The
member functions of a class are also sometimes referred to as methods, although we
will not be using this term.
When you define a class, you define a blueprint for a data type. This doesn’t actu-
ally define any data, but it does define what the class name means, that is, what an
object of the class will consist of and what operations can be performed on such an
object. It’s much the same as if you wrote a description of the basic type double. This
wouldn’t be an actual variable of type double, but a definition of how it’s made up
and how it operates. To create a variable, you need to use a declaration statement.
It’s exactly the same with classes, as you will see.

Defining a Class
Let’s look again at the class we started talking about at the start of the chapter - a
class of boxes. We defined the Box data type using the keyword class as follows:

1 c l a s s Box
2 {
3 public :
4
5 double length ;
7

6
7 double breadth ;
8 double height ;
9 };
10
11
12
13
14
15 // Length of a box in inches
16
17 // Breadth of a box in inches
18 // Height of a box in inches
19

The name that we’ve given to our class appears following the keyword and the
three data members are defined between the curly braces. The data members are
defined for the class using the declaration statements that we already know and love,
and the whole class definition is terminated with a semicolon. The names of all the
members of a class are local to a class. You can therefore use the same names else-
where in a program without causing any problems.

Access Control in a Class


The keyword public looks a bit like a label, but in fact it is more than that. It de-
termines the access attributes of the members of the class that follow it. Specifying
the data members as public means that these members of an object of the class can
be accessed anywhere within the scope of the class object. You can also specify the
members of a class as private or protected. In fact, if you omit the access specifica-
tion altogether, the members have the default attribute, private. We shall look into
the effect of these keywords in a class definition a bit later.

Remember that all we have defined so far is a class, which is a data type. We haven’t
declared any objects of the class. When we talk about accessing a class member, say
height, we’re talking about accessing the data member of a particular object, and that
object needs to be declared somewhere.

Declaring Objects of a Class


We declare objects of a class with exactly the same sort of declaration that we use to
declare objects of basic types. We saw this at the beginning of the chapter. So, we
could declare objects of our class, Box, with these statements:
7 Lab 6:Object Orientation in C+

1 Box Box1 ; Box Box2 //


; Declare Box1 of type Box
2 // Declare Box2 of type Box
3

Both of the objects Box1 and Box2 will, of course, have their own data members. This
is illustrated here:

Figure 6.1:

The object name Box1 embodies the whole object, including its three data mem-
bers. They are not initialized to anything, however - the data members of each object
will simply contain junk values, so we need to look at how we can access them for
the purpose of setting them to some specific values.

Accessing the Data Members of a Class


The data members of objects of a class can be referred to using the direct member
access operator (.). So, to set the value of the data member height of the object Box2
to, say, 18.0, we could write this assignment statement:

Box2.height = 18.0; // Setting the value of a data member

We can only access the data member in this way, in a function outside the class,
because the member height was specified as having public access. If it wasn’t de-
fined as public, this statement would not compile. We’ll see more about this
shortly.

Try It Out - Your First Use of Classes

Let’s have a go at creating a Box class and setting the values of it’s data members.
We’ll try it out in the following console application:

Example 6.1:
7

1 // Creating and using boxes # include <iostream >


2 using namespace std ;
3
4 c l a s s Box // Class d e f i n i t i o n at glob al scope
5 {
6 public :
7
double length ;// Length of a box in inches double breadth ; // Breadth of a box in inches double height ;//
8
};
i n t main ( void )
9
{
10
Box Box1 ;// Declare Box1 of type Box Box Box2 ;// Declare Box2 of type Box
11
double volume = 0 . 0 ;// Store the volume of a box here Box1 . height = 1 8 . 0 ; // Define the values
12 Box1 . length = 7 8 . 0 ; // of the members of Box1 . breadth = 2 4 . 0 ;// the o b j e c t Box1
13
14
15
16
17
18
19
20 Box2 . height = Box1 . height − 1 0 ; // Define Box2
21 Box2 . length = Box1 . length / 2 . 0 ;// members in
22 Box2 . breadth = 0 . 25 ∗ Box1 . length ; // terms of Box1
23 // Calc ulat e volume of Box1
24
25 volume = Box1 . height ∗ Box1 . length ∗ Box1 . breadth ; cout << endl
26 <<" Volume of Box1 = " << volume ; cout << endl
27 <<" Box2 has s ide s which t o t a l "
28 <<Box2 . height + Box2 . length + Box2 . breadth
29 <<" inches . " ;
30 cout << endl// Display the s i z e of a box in memory
31 <<"A Box o b j e c t occupies "
32
33 <<s i z e o f Box1 << " bytes . " ; cout <<endl ; return 0 ;
34 }
35
36
37
38
39

How It Works
Everything here works as we would have expected from our experience with struc-
tures. The definition of the class appears outside of the function main() and, there-
fore, has global scope. This enables objects to be declared in any function in the
program and causes the class to show up in the ClassView once the program has
been compiled.

We’ve declared two objects of type Box within the function main(), Box1 and Box2.
Of course, as with variables of the basic types, the objects Box1 and Box2 are local
to main(). Objects of a class obey the same rules with respect to scope as variables
declared as one of the basic types (such as the variable volume, which is used in this
7 Lab 6:Object Orientation in C+

example).

The first three assignment statements set the values of the data members of Box1.
We define the values of the data members of Box2 in terms of the data members of
Box1 in the next three assignment statements.

We then have a statement which calculates the volume of Box1 as the product of
its three data members. This value is then output to the screen. Next, we output
the sum of the data members of Box2 by writing the expression for the sum of the
data members directly in the output statement. The final action in the program is
to output the number of bytes occupied by Box1, which is produced by the operator
sizeof.

If you run this program, you should get this output:

Figure 6.2:

Note that the Box object is still the same number of bytes. Adding a function
member to a class doesn’t affect the size of the objects. Obviously, a member func-
tion has to be stored in memory somewhere, but there’s only one copy regardless of
how many class objects have been declared, and it isn’t counted when the operator
sizeof produces the number of bytes that an object occupies.

The names of the class data members in the member function automatically refer
to the data members of the specific object used to call the function, and the function
can only be called for a particular object of the class. In this case, this is done by
using the direct member access operator (.) with the name of an object.

If you try to call a member function without specifying an object name, your pro-
gram will not compile.

Positioning a Member Function Definition


A member function definition need not be placed inside the class definition. If you
want to put it outside the class definition, you need to put the prototype for the
7

function inside the class. If we rewrite the previous class with the function definition
outside, then the class definition looks like this:

1 c l a s s Box // Class d e f i n i t i o n at global scope


2 {
3 public :
4 double length ; // Length of a box in inches
5 double breadth ; // Breadth of a box in inches
6
7 double height ; // Height of a box in inches
8 double Volume ( void ) ; // Member function prototype
9 };

Now we need to write the function definition, but there has to be some way of telling
the compiler that the function belongs to the class Box. This is done by prefixing
the function name with the name of the class and separating the two with the scope
resolution operator, ::, which is formed from two successive colons. The function
definition would now look like this:

1 //Function to c a l c u l a t e the volume of a box double Box : : Volume ( void )


2 {
3 return length ∗ breadth ∗ height ;
4 }

It will produce the same output as the last example. However, it isn’t exactly the
same program. In the second case, all calls to the function are treated in the way
that we’re already familiar with. However, when we defined the function within the
definition of the class in Ex6_02.cpp, the compiler implicitly treated the function as
an inline function.

Inline Functions

With an inline function, the compiler tries to expand the code in the body of the func-
tion in place of a call to the function. This avoids much of the overhead of calling the
function and, therefore, speeds up your code. This is illustrated here:
7 Lab 6:Object Orientation in C+

Figure 6.3:

Of course, the compiler takes care of ensuring that expanding a function inline
doesn’t cause any problems with variable names or scope.

The compiler may not always be able to insert the code for a function inline (such
as with recursive functions or functions for which you have obtained an address),
but generally it will work. It’s best used for very short, simple functions, such as our
function Volume(), because they will execute faster and will not significantly increase
the size of the executable module.

With the function definition outside of the class definition, the compiler treats
the function as a normal function and a call of the function will work in the usual
way. However, it’s also possible to tell the compiler that, if possible, we would like
the function to be considered as inline. This is done by simply placing the keyword
inline at the beginning of the function header. So, for our function, the definition
would be as follows:

// Function to calculate the volume of a box inline double Box::Volume(void)


{
return length * breadth * height;
}

With this definition for the function, the program would be exactly the same as
the original. This allows you to put the member function definitions outside of the
class definition, if you so choose, and still retain the speed benefits of inlining.

You can apply the keyword inline to ordinary functions in your program that
have nothing to do with classes and get the same effect. However, remember that
it’s best used for short, simple functions.
7

We now need to understand a little more about what happens when we declare
an object of a class.

Note:
Before doing your lab exercises run the examples.

Exercise:
Q1: write a class for addition of complex numbers. The program should ask for real
and imaginary part of complex numbers and using function it should add the real
part to real part of the number and imaginary part to imaginary part of the
number.

Q2: Write program using class Geometry. The program should ask the user for
length and width if the length and width both are same then it should call square
function to calculate its area and parameter otherwise it should call rectangle func-
tion to calculate the area and parameter of the rectangle.
8 Lab 6:Object Orientation in C+
Chapter 7

Lab 7:Object Orientation in C++ II

Class Constructors
In the previous program, we declared our Box objects, Box1 and Box2, and then labo-
riously worked through each of the data members for each object, in order to assign
an initial value to it. This is unsatisfactory from several points of view. First of all,
it would be easy to overlook initializing a data member, particularly in the case of a
class which had many more data members than our Box class. Initializing the data
members of several objects of a complex class could involve pages of assignment
statements. The final constraint on this approach arises when we get to defining data
members of a class that don’t have the attribute public - we won’t be able to access
them from outside the class anyway. There has to be a better way, and of course there
is - it’s known as the class constructor.

What is a Constructor?

A class constructor is a special function in a class that is called when a new ob-
ject of the class is declared. It therefore provides the opportunity to initialize
objects as they are created and to ensure that data members only contain valid
values.

You have no leeway in naming a class constructor - it always has the same name
as the class in which it is defined. The function Box(), for example, is a constructor
for our Box class. It also has no return type. It’s wrong to specify a return type for
a constructor; you must not even write it as void. The primary function of a class
constructor is to assign initial values to the data elements of the class, and no return
type is necessary or, indeed, permitted.

Try It Out - Adding a Constructor to the Box class Let’s extend our Box class to
incorporate a constructor.

Example 7.1:

81
8 Lab 7:Object Orientation in C++

1 // Usinga c o n s t r uc t o r # include <iostream >


2 using namespace std ;
3 c l a s s Box// Class d e f i n i t i o n at glob al scope
4 {
5
public :
double length ;// Length of a box in inches double breadth ; // Breadth of a box in inches double height ;// Height
6
//Constructor d e f i n i t i o n
7
Box ( double lv , double bv , double hv )
8
{
9
cout << endl << " Constructor c a l l e d . " ; length = lv ;// Set values of
10 breadth = bv ; // data members height = hv ;
11 }
12
13
14
15
16
17
18
19
20
21 FCS&E , GIK I n s t i t u t e Topi , Pakistan Page 64
22
23 CS102L : I n t e n s i ve Programming Lab
24
25
26
27
28
29
30 //Function to c a l c u l a t e the volume of a box double Volume ( )
31
32 {
33 return length ∗ breadth ∗ height ;
34 }
35 };
36
37 i n t main ( void )
38
39 {
40
41
42 Box Box1 ( 7 8 . 0 , 2 4 . 0 , 1 8 . 0 ) ; Box CigarBox ( 8 . 0 , 5 . 0 , 1 . 0 ) ;
43
44 // Declare and i n i t i a l i z e Box1
45
46 // Declare and i n i t i a l i z e CigarBox
47
48
49 double volume = 0 . 0 ; volume = Box1 . Volume ( ) ;
50
51
52 // Store the volume of a box here // Calc ulat e volume of Box1
53
54
8

55 cout << endl


56
57 << " Volume of Box1 = " << volume ; cout << endl
58
59 << " Volume of CigarBox = "
60 << CigarBox . Volume ( ) ;
61 cout << endl ;
62
63 return 0;
64
65 }

How It Works
The constructor, Box(), has been written with three parameters of type double, cor-
responding to the initial values for the length, breadth and height members of a Box
object. The first statement in the constructor outputs a message so that we can tell
when it’s been called. You wouldn’t do this in production programs, but, since it’s
very helpful in showing when a constructor is called, it’s often used when testing
a program. We’ll use it regularly for the purposes of illustration. The code in the
body of the constructor is very simple. It just assigns the arguments passed to the
corresponding data members. If necessary, we could also include checks that valid,
non-negative arguments are supplied and, in a real context, you probably would
want to do this, but our primary interest here is in seeing how the mechanism works.

Within main(), we declare the object Box1 with initializing values for the data
members length, breadth, and height, in sequence. These are in parentheses follow-
ing the object name. This uses the functional notation for initialization, which can
also be applied to initializing ordinary variables of basic types. We also declare a
second object of type Box, called CigarBox, which also has initializing values.

The volume of Box1 is calculated using the member function Volume() as in the
previous example and is then displayed on the screen. We also display the value of
the volume of CigarBox. The output from the example is:

Figure 7.1:

The first two lines are output from the two calls of the constructor, Box(), once for
each object declared. The constructor that we’ve supplied in the class definition is
8 Lab 7:Object Orientation in C++

automatically called when a Box object is declared, so both Box objects are
initialized with the initializing values appearing in the declaration. These are
passed to the constructor as arguments, in the sequence that they are written in
the declaration. As you can see, the volume of Box1 is the same as before and

CigarBox has a volume looking suspiciously like the product of its dimensions,
which is quite a relief.

The Default Constructor


Try modifying the last example by adding the declaration for Box2 that we had pre-
viously:

Box Box2; // Declare Box2 of type Box

Here, we’ve left Box2 without initializing values. When you rebuild this version
of the program, you’ll get the error message:

error C2512: ’Box’: no appropriate default constructor available


This means that the compiler is looking for a default constructor for Box2, either one
that needs no arguments, because none are specified in the constructor definition,
or one whose arguments are all optional, because we haven’t supplied any initializ-
ing values for the data members. Well, this statement was perfectly satisfactory in
Ex6_02.cpp, so why doesn’t it work now?

The answer is that the previous example used a default constructor that was sup-
plied by the compiler, because we didn’t supply one. Since in this example we did
supply a constructor, the compiler assumed that we were taking care of everything
and didn’t supply the default. So, if you still want to use declarations for Box objects
which aren’t initialized, you have to include the default constructor yourself. What
exactly does the default constructor look like? In the simplest case, it’s just a con-
structor that accepts no arguments, it doesn’t even need to do anything:
Box() { }
// Default constructor

// Totally devoid of statements


8

Try It Out - Supplying a Default Constructor


Let’s add our version of the default constructor to the last example, along with the
declaration for Box2, plus the original assignments for the data members of Box2.
We must enlarge the default constructor just enough to show that it is called. Here
is the next version of the program:

1 //Supplying and using a de fa ult c o n s t r uc t o r # include <iostream >


2
3 using namespace std ;
4
5 c l a s s Box //Class d e f i n i t i o n at glob al scope
6 {
7 public :
8 double length ;//
9 Length of a box in inches Breadth of a box in inches Height of a box in inches
10 double breadth ; // double height ;//
11
12 // Constructor d e f i n i t i o n
13 Box ( double lv ,doublebv , double hv )
14
15 {
16 cout << endl << " Constructor c a l l e d . " ; length = lv ;// Set values of
17
18 breadth = bv ; // data members height = hv ;
19 }
20
21 //Default c o n s t r uc t o r d e f i n i t i o n Box ( )
22
23 { cout << endl << " Default c o n s t r uc t o r c a l l e d . " ; }
24
25 //Function to c a l c u l a t e the volume of a box double Volume ( )
26 {
27
28
29 return length ∗ breadth ∗ height ;
30 }
31 };
32 i n t main ( void )
33
{
34
Box Box1 ( 7 8 . 0 , 2 4 . 0 , 1 8 . 0 ) ; //Declare and i n i t i a l i z e Box1
35 Box Box2 ; //Declare Box2 − no i n i t i a l values
36 Box CigarBox ( 8 . 0 , 5 . 0 , 1 . 0 ) ;// Declare and i n i t i a l i z e CigarBox the volume of a box here
37 double volume = 0 . 0 ;//Store
38 volume = Box1 . Volume ( ) ; //C a l c u l at e volume of Box1
39
8 Lab 7:Object Orientation in C++

40 cout << endl


41 << " Volume of Box1 = " << volume ;
42
43
44 Box2 . height = Box1 . height − 1 0 ; Box2 . length = Box1 . length / 2 . 0 ; Box2 . breadth
= 0 . 25 ∗ Box1 . length ;
45 cout << endl
46
47
48 <<" Volume of Box2 = "
49 <<Box2 . Volume ( ) ; cout << endl
50 <<" Volume of CigarBox = "
51 <<CigarBox . Volume ( ) ; cout << endl ;
52
53 return 0;
54
55 }
56
57
58
59
60
61
62 //Define Box2
63
64 //members in
65
66 //terms of Box1
67

How It Works
Now that we have included our own version of the default constructor, there are no
error messages from the compiler and everything works. The program produces this
output:

Figure 7.2:

All that our default constructor does is to display a message. Evidently, it was
8

called when we declared the object Box2. We also get the correct value for the vol-
umes of all three Box objects, so the rest of the program is working as it should.
One aspect of this example that you may have noticed is that we now know
we can overload constructors just as we overloaded functions. We’ve just run an
example with two constructors that differ only in their parameter list. One has three
parameters of type double and the other has no parameters at all.

Assigning Default Values in a Constructor


When we discussed functions in C++, we saw how we could specify default val-
ues for the parameters to a function in the function prototype. We can also do this
for class member functions, including constructors. If we put the definition of the
member function inside the class definition, we can put the default values for the
parameters in the function header. If we only include the prototype of a function in
the class definition, the default parameter value should go in the prototype.

If we decided that the default size for a Box object was a unit box with all sides
of length 1, we could alter the class definition in the last example to this:

1
2 c l a s s Box // Class d e f i n i t i o n at glob al scope
3
4 {
5 public :
6 double length ;// Length of a box in inches
7
8 double breadth ; // Breadth of a box in inches double height ;// Height of a box in inches
9
10 // Constructor d e f i n i t i o n
11
12 Box ( double lv = 1 . 0 , double bv = 1 . 0 , double hv = 1 . 0 )
13 {
14 cout << endl << " Constructor c a l l e d . " ;
15
16 length = lv ;// Set values of breadth = bv ; // data members height = hv ;
17 }
18 // Default c o n s t r uc t o r d e f i n i t i o n Box ( )
19 { cout << endl << " Default c o n s t r uc t o r c a l l e d . " ; }
20
21 // Function to c a l c u l a t e the volume of a box double Volume ( )
22 {
23 return length ∗ breadth ∗ height ;
24
25
26
27
28
29
30
8 Lab 7:Object Orientation in C++

31 }
32 };

If we make this change to the last example, what happens? We get another error
message from the compiler, of course. We get these useful comments:

warning C4520: ’Box’: multiple default constructors specified

error C2668: ’Box::Box’: ambiguous call to overloaded function


This means that the compiler can’t work out which of the two constructors to call -
the one for which we have set default values for the parameters or the constructor
that doesn’t accept any parameters. This is because the declaration of Box2 requires
a constructor without parameters, and either constructor can now be called in this
case. The immediately obvious solution to this is to get rid of the constructor that
accepts no parameters. This is actually beneficial. Without this constructor, any Box
object that is declared without being explicitly initialized will automatically have its
members initialized to 1.

Try It Out - Supplying Default Values for Constructor Argu-


ments
We can demonstrate this with the following simplified example:

Example 7.2:

1 // Supplying de fa ult values fo r c o n s t r uc t o r arguments # include <iostream >


2
3 using namespace std ;
4
5 c l a s s Box // Class d e f i n i t i o n at global scope
6 {
7 public :
8 double length ; // Length of a box in inches
9 double breadth ; // Breadth of a box in inches
10 double height ; // Height of a box in inches
11
12 // Constructor d e f i n i t i o n
13 Box ( double lv = 1 . 0 , double bv = 1 . 0 , double hv = 1 . 0 )
14 {
15
16 cout << endl << " Constructor c a l l e d . " ;
17 length = lv ; // Set values of
18 breadth = bv ; // data members
8

19 height = hv ;
20 }
21 // Function to c a l c u l a t e the volume of a box double Volume ( )
22 {
23
24
25
26 return length ∗ breadth ∗ height ;
27 }
28 };
29
30 i n t main ( void )
31 {
32 Box Box2 ; // Declare Box2 − no i n i t i a l values
33 cout << endl
34 << " Volume of Box2 = "
35 << Box2 . Volume ( ) ; cout << endl ;
36 return 0 ;
37
38 }
39
40

How It Works

We only declare a single uninitialized Box variable, Box2, because that’s all we need
for demonstration purposes. This version of the program produces the following
output:

Figure 7.3:

This shows that the constructor with default parameter values is doing its job of
setting the values of objects that have no initializing values specified.
You shouldn’t assume from the above example that this is the only, or even the
recommended, way of implementing the default constructor. There will be many
occasions where you won’t want to assign default values in this way, in which case
you’ll need to write a separate default constructor. There will even be times when
you don’t want to have a default constructor operating at all, even though you have
defined another constructor. This would ensure that all declared objects of a class
must have initializing values explicitly specified in their declaration.
9 Lab 7:Object Orientation in C++

Using an Initialization List in a Constructor


Previously, we initialized the members of an object in the class constructor using
explicit assignment. We could also have used a different technique, using what is
called an initialization list. We can demonstrate this with an alternative version of
the constructor for the class Box:
1 // Constructor d e f i n i t i o n using an i n i t i a l i z a t i o n l i s t Box ( double lv = 1 .
0 , double bv = 1 . 0 , double hv = 1 . 0 ) : length ( lv ) ,
2
3 breadth ( bv ) ,
4 height ( hv )
5 {
6 cout << endl << " Constructor called . " ;
7 }

Now the values of the data members are not set in assignment statements in the
body of the constructor. As in a declaration, they are specified as initializing values
using functional notation and appear in the initializing list as part of the function
header. The member length is initialized by the value of lv, for example. This can
be rather more efficient than using assignments as we did in the previous version. If
you substitute this version of the constructor in the previous example, you will see
that it works just as well.

Note that the initializing list for the constructor is separated from the parameter
list by a colon and that each of the initializers is separated by a comma. This tech-
nique for initializing parameters in a constructor is important, because, as we shall
see later, it’s the only way of setting values for certain types of data members of an
object.

Private Members of a Class


Having a constructor that sets the values of the data members of a class object, but
still admits the possibility of any part of a program being able to mess with what
are essentially the guts of an object, is almost a contradiction in terms. To draw an
analogy, once you have arranged for a brilliant surgeon such as Dr. Kildare, whose
skills were honed over years of training, to do things to your insides, letting the local
plumber, bricklayer or the folks from Hill Street Blues have a go hardly seems appro-
priate. We need some protection for our class data members.

We can get it by using the keyword private when we define the class members. Class
members which are private can, in general, only be accessed by member functions
of a class. There’s one exception, but we’ll worry about that later. A normal
function has no direct means of accessing the private members of a class. This is
shown here:
9

Figure 7.4:

Having the possibility of specifying class members as private also enables you
to separate the interface to the class from its internal implementation. The
interface to a class is composed of the public members and the public member
functions in par- ticular, since they can provide indirect access to all the members
of a class, including the private members. By keeping the internals of a class
private, you can later mod- ify them to improve performance, for example, without
necessitating modifications to the code that uses the class through its public
interface. To keep them safe from unnecessary meddling, it’s good practice to
declare data and function members of a class that don’t need to be exposed as
private. Only make public what is essential to the use of your class.

Try It Out - Private Data Members


We can rewrite the Box class to make its data members private.
1 // A c l a s s with pr i va t e members
2 # include <iostream >
3
4 using namespace std ;
5 c l a s s Box
6 {
7
8
9
10
11
12
13
14 // Class d e f i n i t i o n at global scope
15
9 Lab 7:Object Orientation in C++

16 public :
17 // Constructor d e f i n i t i o n
18 Box ( double lv = 1 . 0 , double bv = 1 . 0 , double hv = 1 . 0 )
19 {
20
21 cout << endl << " Constructor c a l l e d . " ; length = lv ;// Set values of
22
breadth = bv ; // data members height = hv ;
23
}
24
25
26
27
28 //Function to c a l c u l a t e the volume of a box double Volume ( )
29 {
30 return length ∗ breadth ∗ height ;
31 }
32
33
34 pr iva t e :
35 double length ;
36
37 double breadth ; double height ;
38
39
40
41
42 // Length of a box in inches // Breadth of a box in box inches
in inches
// Height of a

43
44 };
45 i n t main ( void )
46 {
47
48 Box Match ( 2 . 2 , 1 . 1 , 0 . 5 ) ; // Declare Match box Box Box2 ; // Declare Box2 − no i n i t i a l values
49
50 cout << endl
51
52 <<" Volume of Match = "
53 <<Match . Volume ( ) ;
54
55 //Uncomment the following l i n e to get an e r r o r
56
57 //Box2 . length = 4 . 0 ; cout << endl
58 <<" Volume of Box2 = "
59 <<Box2 . Volume ( ) ; cout << endl ;
60
61 return 0;
62 }
63
64
65
9

How It Works

The definition of the class Box now has two sections. The first is the public section
containing the constructor and the member function Volume(). The second section
is specified as private and contains the data members. Now the data members can
only be accessed by the member functions of the class. We don’t have to modify any
of the member functions - they can access all the data members of the class anyway.
However, if you uncomment the statement in the function main(), assigning a value
to the member length of the object Box2, you’ll get a compiler error message con-
firming that the data member is inaccessible.

A point to remember is that using a constructor or a member function is now the


only way to get a value into a private data member of an object. You have to make
sure that all the ways in which you might want to set or modify private data mem-
bers of a class are provided for through member functions.
We could also put functions into the private section of a class. In this case, they can
only be called by other member functions. If you put the function Volume() in the
private section, you will get a compiler error from the statements that attempt to use
it in the function main(). If you put the constructor in the private section, you won’t
be able to declare any members of the class.

The above example generates this output:

Figure 7.5:

This demonstrates that the class is still working satisfactorily, with its data mem-
bers defined as having the access attribute private. The major difference is that they
are now completely protected from unauthorized access and modification.

If you don’t specify otherwise, the default access attribute which applies to mem-
bers of a class is private. You could, therefore, put all your private members at the
beginning of the class definition and let them default to private by omitting the key-
word. However, it’s better to take the trouble to explicitly state the access attribute
in every case, so there can be no doubt about what you intend.
9 Lab 7:Object Orientation in C++

Of course, you don’t have to make all your data members private. If the applica-
tion for your class requires it, you can have some data members defined as private
and some as public. It all depends on what you’re trying to do. If there’s no reason
to make members of a class public, it is better to make them private as it makes
the class more secure. Ordinary functions won’t be able to access any of the private
members of your class.

Accessing private Class Members


On reflection, declaring all the data members of a class as private might seem
rather extreme. It’s all very well protecting them from unauthorized modification, but
that’s no reason to keep their values a secret. What we need is a Freedom of
Information Act for private members.

You don’t need to start writing to your state senator to get it - it’s already avail-
able to you. All you need to do is to write a member function to return the value of
a data member. Look at this member function for the class Box:

1 i n l i n e double Box : : GetLength ( void )


2 {
3 return length ;
4 }

Just to show how it looks, this has been written as a member function definition
which is external to the class. We’ve specified it as inline, since we’ll benefit from
the speed increase, without increasing the size of our code too much. Assuming that
you have the declaration of the function in the public section of the class, you can
use it by writing this statement:

1 len = Box2 . GetLength ( ) ; // Obtain data member length

All you need to do is to write a similar function for each data member that you
want to make available to the outside world, and their values can be accessed
without prejudicing the security of the class. Of course, if you put the definitions for
these functions within the class definition, they will be inline by default.

The Default Copy Constructor


Suppose we declare and initialize a Box object Box1 with this statement:
9

Box Box1(78.0, 24.0, 18.0);

We now want to create another Box object, identical to the first. We would like
to initialize the second Box object with Box1.

Try It Out - Copying Information Between Instances


We can try this out with the main() function which follows:

Example 7.3:

1
2 //I n i t i a l i z i n g an o b j e c t with an o b j e c t of the same c l a s s # include < iostream >
using namespace std ;
3
4
5
6 c l a s s Box {
7
8
9 // Class d e f i n i t i o n at gl ob al scope
10
11
12 public :
13 // Constructor d e f i n i t i o n
14 Box ( double lv = 1 . 0 , double bv = 1 . 0 , double hv = 1 . 0 )
15 {
16
cout << endl << " Constructor c a l l e d . " ; length = lv ;// Set values of
breadth = bv ; // data members
17
18
19
height = hv ;
}
20
21
22
23
24 //Function to c a l c u l a t e the volume of a box double Volume ( )
25
26 {
27 return length ∗ breadth ∗ height ;
28 }
29
30 pr iva t e :
31 double length ;// Length ofa box ininches double breadth ; //Breadth of a box in inches
32 double height ;//Heightofa box ininches
33
34
9 Lab 7:Object Orientation in C++

35 };
36
37 i n t main ( void )
38 {
39
40
41 Box Box1 ( 7 8 . 0 , 2 4 . 0 , 1 8 . 0 ) ; Box Box2 = Box1 ;
42
43
44 // I n i t i a l i z e Box2 with Box1
45
46
47 cout << endl
48 << " Box1 volume = " << Box1 . Volume ( )
49 << endl
50 << " Box2 volume = " << Box2 . Volume ( ) ;
51
52 cout << endl ;
53
54 return 0;
55 }

How It Works
This example will produce this:

Figure 7.6:

Clearly, the program is working as we would want, with both boxes having the
same volume. However, as you can see from the output, our constructor was called
only once for the creation of Box1. But how was Box2 created? The mechanism is
similar to the one that we experienced when we had no constructor defined and the
compiler supplied a default constructor to allow an object to be created. In this case,
the compiler generates a default version of what is referred to as a copy constructor.
A copy constructor does exactly what we’re doing here - it creates an object of a
class by initializing it with an existing object of the same class. The default version of
the copy constructor creates the new object by copying the existing object, member
by member.
This is fine for simple classes such as Box, but for many classes - classes that have
pointers or arrays as members for example - it won’t work properly. Indeed, with
9

such classes it can create serious errors in your program. In these cases, you need to
create your own class copy constructor.

Destructor:

A destructor is a special member function of a class that is executed whenever an


object of it’s class goes out of scope or whenever the delete expression is applied to
a pointer to the object of that class.
A destructor will have exact same name as the class prefixed with a tilde ( ) and
it can neither return a value nor can it take any parameters. Destructor can be very
useful for releasing resources before coming out of the program like closing files,
releasing memories etc.

Example 7.4:

1 # include <iostream >


2 using namespace std ;
3
4 class CRectangle
5 { i n t width , height ;
6 public :
7
8 CRectangle ( i n t a , i n t b )
9
10 { width = a ; height = b ;
11 }
12
13 i n t area ( )
14 { return ( width ∗ height ) ; }
15
16 ~CRectangle ( ) {
17
18 cout <<" de l e t i n g o b j e c t . . . " <<endl ;
19 }
20 };
21
22 i n t main ( ) {
23
24 CRectangle r e c t ( 3 , 4 ) ;
25 CRectangle r e c t b ( 5 , 6 ) ;
26 cout << " r e c t area : " << r e c t . area ( ) << endl ;
27 cout << " r e c t b area : " << r e c t b . area ( ) << endl ;
28
29 return 0 ;
30
31 }
9 Lab 7:Object Orientation in C++

Note:
Before doing your lab exercises run the examples.

Exercise:
Q1: Write a C++ program to make a car class with wheels, doors as private data
members and cur_speed as public data member while speed and break as public
member functions. Use constructor with default value of wheels=4,doors=2 and
cur_speed=0 for initialization. Make two objects in the name of ferrari and hino.
Ferrari is initialized through default values while hino has 10 wheels, 4 doors. Every
time when you call speed function cur_speed is increased by 5 while break function
decrease it by 5. Display current speed.

Q1: Make a class in the name of circle with data memberâ A˘ Z´ s radius,
perimeter, and area. Use overloaded constructor one with no argument which
initializes ra- dius=1. The other constructor accepts argument of radius and
initializes. Make two objects circle1 and circle2, circle with no values and circle2
with any input value en- tered in run time from your keyboard. Find area and
perimeter of both circles and display them. Also modify destructor code which
display which circle with area is deleted. Formulas: Area=ÏA˘ r2ˆ perimeter=2ÏA˘ r
Chapter 8

Lab 8:Friend Function & Classes,


This Pointer, and static Variables

Friend Classes
C++ provides the friend keyword to do just this. Inside a class, you can indicate that
other classes (or simply functions) will have direct access to protected and private
members of the class. When granting access to a class, you must specify that the
access is granted for a class using the class keyword:

friend class aClass;

Note that friend declarations can go in either the public, private, or protected section
of a class–it doesn’t matter where they appear. In particular, specifying a friend in
the section marked protected doesn’t prevent the friend from also accessing private
fields.

Here is a more concrete example of declaring a friend:

1 c l a s s Node
2
3 {
4
5 pr iva t e :
6
7 i n t data ;
8
9 i n t key ;
10
11 // . . .
12
13 f r i e n d c l a s s Binary Tree ; // c l a s s Binary Tree can now ac c e s s data d i r e c t l y
14
15 };

99
1 Lab 8:Friend Function & Classes, This Pointer, and static

Now, Node does not need to provide any means of accessing the data stored in the
tree. The BinaryTree class that will use the data is the only class that will ever need
access to the data or key. (The BinaryTree class needs to use the key to order the tree,
and it will be the gateway through which other classes can access data stored in any
particular node.)

Now in the BinaryTree class, you can treat the key and data fields as though they
were public:

1 c l a s s Binary Tree
2
3 {
4
5 pr iva t e :
6
7 Node ∗ root ;
8
9 i n t f ind ( i n t key ) ;
10
11 };
12
13 i n t Binary Tree : : f ind ( i n t key )
14
15 {
16
17 // check root fo r NULL . . .
18
19 i f ( root −>key == key )
20
21 {
22
23 // no need to go through an ac c e s s or function return root −>data ;
24
25 }
26
27 // perform r e s t of f ind

Friend Functions
Similarly, a class can grant access to its internal variables on a more selective
basis– for instance, restricting access to only a single function. To do so, the entire
function signature must be replicated after the friend specifier, including the return
type of the function–and, of course, you’ll need to give the scope of the function if
it’s inside another class:

friend return_type class_name::function(args);


1

For instance, in our example Node class, we would use this syntax:

1 c l a s s Node
2
3 {
4
5 pr iva t e :
6
7 i n t data ;
8
9 i n t key ;
10
11 // . . .
12
13 f r i e n d i n t Binary Tree : : f ind ( ) ; // Only Binary Tree ’ s f ind function has ac c e
14 ss
15
};
Now the find function of BinaryTree could access the internals of the Node class,
but no other function in BinaryTree could. (Though we might want a few others to
be able to!)

Note that when friends are specified within a class, this does not give the class
itself access to the friend function. That function is not within the scope of the class;
it’s only an indication that the class will grant access to the function.

Functions which are friends of a class and are defined within the class definition
are also by default inline.

Friend functions are not members of the class, and therefore the access attributes
do not apply to them. They are just ordinary global functions with special privileges.

Let’s suppose that we wanted to implement a friend function in the Box class to
compute the surface area of a Box object.

Try It Out - Using a friend to Calculate the Surface Area


We can see how this works in the following example:

Example 8.1
1 Lab 8:Friend Function & Classes, This Pointer, and static

1 // Creating a f r i e n d f unc t i on of a c l a s s
2
3 # include <iostream > using namespace std ;
4
5
6
7 c l a s s Box
8
9 {
10
11
12 // Class d e f i n i t i o n at gl ob a l scope
13
14 public :
15 // Constructor d e f i n i t i o n
16
17 Box ( double lv = 1 . 0 , double bv = 1 . 0 , double hv = 1 . 0 )
18 {
19 cout << endl << " Constructor c a l l e d . " ; length = lv ;// Set values of
20 breadth = bv ; // data members
21
22 height = hv ;
23
}
24
25
26
27 //Function to c a l c u l a t e the volume of a box double Volume ( )
28
29 {
30 return length ∗ breadth ∗ height ;
31 }
32
33 pr iva t e :
34 double length ;// Length ofa box ininches double breadth ; //Breadth of a box in inches
35 double height ;//Heightofa box ininches
36
37 //Friend f unc t i on
38
39 f r i e n d double Box Surface ( Box aBox ) ;
40 };
41
42 //f r i e n d f unc t i on to c a l c u l a t e the s ur fa c e area of a Box o b j e c t double Box Surface ( Box aBox )
43
{
44
45
46 return 2 . 0 ∗ ( aBox . length ∗aBox . breadth +
47 aBox . length ∗aBox . height +
48 aBox . height ∗aBox . breadth ) ;
49 }
50
51 i n t main ( void )
52 {
53 Box Match ( 2 . 2 , 1.1 , 0 . 5 ) ; // Declare Match box
1

54 Box Box2 ; // Declare Box2 − no i n i t i a l values


55
56 cout << endl
57 << " Volume of Match = "
58 << Match . Volume ( ) ;
59
60 cout << endl
61
62 << " Surface area of Match = "
63 << Box Surface ( Match ) ;
64
65 cout << endl
66
67 << " Volume of Box2 = "
68 << Box2 . Volume ( ) ;
69
70 cout << endl
71
72 << " Surface area of Box2 = "
73 << Box Surface ( Box2 )
74 ; cout << endl ;
75
76 return 0;
77 }

How It Works

We declare the function BoxSurface() as a friend of the Box class by writing the func-
tion prototype with the keyword friend at the front. Since the BoxSurface() function
itself is a global function, it makes no difference where we put the friend declaration
within the definition of the class, but it’s a good idea to be consistent when you po-
sition this sort of declaration. You can see that we have chosen to position ours after
all the public and private members of the class. Remember that a friend function
isn’t a member of the class, so access attributes don’t apply.

The definition of the function follows that of the class. Note that we specify ac-
cess to the data members of the object within the definition of BoxSurface(), using
the Box object passed to the function as a parameter. Because a friend function isn’t
a class member, the data members can’t be referenced just by their names. They each
have to be qualified by the object name in exactly the same way as they might in
an ordinary function, except, of course, that an ordinary function can’t access the
private members of a class. A friend function is the same as an ordinary function
except that it can access all the members of a class without restriction.

The example produces this output:


1 Lab 8:Friend Function & Classes, This Pointer, and static

Figure 8.1:

This is exactly what you would expect. The friend function is computing the sur-
face area of the Box objects from the values of the private members.

Placing friend Function Definitions Inside the Class


We could have combined the definition of the function with its declaration as a friend
of the Box class within the class definition - the code would run as before. However,
this has a number of disadvantages relating to the readability of the code. Although
the function would still have global scope, this wouldn’t be obvious to readers of
the code, since the function would be hidden in the body of the class definition, and
particularly since the function would no longer show up in the ClassView.

The this pointer


Every object in C++ has access to its own address through an important pointer
called this pointer. The this pointer is an implicit parameter to all member functions.
Therefore, inside a member function, this may be used to refer to the invoking object.

Friend functions do not have a this pointer, because friends are not members of a
class. Only member functions have a this pointer.

Let us try the following example to understand the concept of this pointer:

1 # include <iostream >


2
3 using namespace std ;
4 c l a s s Box
5 {
6 public :
7 // Constructor d e f i n i t i o n
1

8 Box ( double l = 2 . 0 , double b = 2 . 0 , double h = 2 . 0 )


9 {
10 cout <<" Constructor c a l l e d . " << endl ; length = l ;
11 breadth = b ;
12
13 height = h ;
14
}
15
double Volume ( )
{
16
17
18 return length ∗ breadth ∗ height ;
19 }
20 i n t compare ( Box box )
21 {
22 return t his −>Volume ( ) > box . Volume ( ) ;
23 }
24 pr iva t e :
25 double length ; // Length of a box
26 double breadth ; // Breadth of a box
27 double height ;// Height of a box
28 };
29 i n t main ( void )
30 {
31
Box Box1 ( 3 . 3 , 1 . 2 , 1 . 5 ) ; // Declare box1
Box Box2 ( 8 . 5 , 6 . 0 , 2 . 0 ) ; // Declare box2
32
i f ( Box1 . compare ( Box2 ) )
33
{
34
35
36 cout << " Box2 i s smaller than Box1 " <<endl ;
37
38 }
39 else
40 {
41 cout << " Box2 i s equal to or l a r g e r than Box1 " <<endl ;
42
}
43
return 0 ;
}
44

When the above code is compiled and executed, it produces following result:
Constructor called.
Constructor called.
Box2 is equal to or larger than Box1

Static keyword in C++


Static variables keep their values and are not destroyed even after they go out of
scope.
For example:

1 i n t GenerateID ( )
1 Lab 8:Friend Function & Classes, This Pointer, and static

2 {
3 s t a t i c i n t s_nID = 0 ;
4 return s_nID ++;
5 }
6
7 i n t main ( )
8 {
9
10 std : : cout << GenerateID ( ) << std : : endl ;
11
12 std : : cout << GenerateID ( ) << std : : endl ;
13
14 std : : cout << GenerateID ( ) << std : : endl ;
15 return 0 ;
16 }

This program prints:

0
1

Note that s_nID has kept itâ A˘ Z´ s value across multiple function calls.

The static keyword has another meaning when applied to global variables â A˘ Tˇ it
changes them from global scope to file scope. Because global variables are typically
avoided by competent programmers, and file scope variables are just global variables
limited to a single file, the static keyword is typically not used in this capacity.

Static member variables


When we instantiate a class object, each object gets itâ A˘ Z´ s own copy of all
normal member variables. Member variables of a class can be made static by using the
static keyword. Static member variables only exist once in a program regardless of
how many class objects are defined! One way to think about it is that all objects of a
class share the static variables. Consider the following program:

1 c l a s s Something
2
3 {
4 public :
5 s t a t i c i n t s_nValue ;
6 };
7
8 i n t Something : : s_nValue = 1 ;
1

9
10 i n t main ( )
11 {
12 Something c F i r s t ;
13 c F i r s t . s_nValue = 2 ;
14
15 Something cSecond ;
16
17 std : : cout << cSecond . s_nValue ;
18
19 return 0;
20 }

This program produces the following output:

Because s_nValue is a static member variable, s_nValue is shared between all ob-
jects of the class. Consequently, cFirst.s_nValue is the same as cSecond.s_nValue.
The above program shows that the value we set using cFirst can be accessed using
cSecond!

Although you can access static members through objects of the class type, this is
somewhat misleading. cFirst.s_nValue implies that s_nValue belongs to cFirst, and
this is really not the case. s_nValue does not belong to any object. In fact, s_nValue
exists even if there are no objects of the class have been instantiated!

Consequently, it is better to think of static members as belonging to the class it-


self, not the objects of the class. Because s_nValue exists independently of any class
objects, it can be accessed directly using the class name and the scope operator:

1 c l a s s Something
2 {
3 public :
4 s t a t i c i n t s_nValue ;
5 };
6
7 i n t Something : : s_nValue = 1
8
9 ; i n t main ( )
10 {
11 Something : : s_nValue = 2 ;
12
13 std : : cout << Something : : s_nValue ;
14
15 return 0 ;
16 }

In the above snippet, s_nValue is referenced by class name rather than through an
1 Lab 8:Friend Function & Classes, This Pointer, and static

object. Note that we have not even instantiated an object of type Something, but we
are still able to access and use Something::s_nValue. This is the preferred method
for accessing static members.

Initializing static member variables


Because static member variables are not part of the individual objects, you must ex-
plicitly define the static member if you want to initialize it to a nonzero value. The
following line in the above example initializes the static member to 1:

int Something::s_nValue = 1;

This initializer should be placed in the code file for the class (eg. Something.cpp). In
the absense of an initializing line, C++ will initialize the value to 0.

An example of static member variables

Why use static variables inside classes? One great example is to assign a unique
ID to every instance of the class. Hereâ A˘ Z´ s an example of that:

1 c l a s s Something
2 {
3 pr iva t e :
4 s t a t i c i n t s_nIDGenerator
5 ; i n t m_nID ;
6 public :
7 Something ( ) { m_nID = s_nIDGenerator ++; }
8
9 i n t GetID ( ) const { return m_nID ; }
10 };
11
12 i n t Something : : s_nIDGenerator = 1 ;
13
14 i n t main ( )
15 {
16 Something c F i r s t ;
17 Something cSecond ;
18
19 Something c Third ;
20
21 using namespace std ;
22 cout << c F i r s t . GetID ( ) << endl ;
23 cout << cSecond . GetID ( ) << endl ;
24 cout << c Third . GetID ( ) << endl ;
1

25 return 0;
26 }

This program prints:

1
2

Because s_nIDGenerator is shared by all Something objects, when a new Something


object is created, itâ A˘ Z´ s constructor grabs the current value out of
s_nIDGenerator and then increments the value for the next object. This guarantees
that each Some- thing object receives a unique id (incremented in the order of
creation). This can really help when debugging multiple items in an array, as it
provides a way to tell multiple objects of the same class type apart!

Static member variables can also be useful when the class needs to utilize an in-
ternal lookup table (eg. to look up the name of something, or to find a precalculated
value). By making the lookup table static, only one copy exists for all objects, rather
than a copy for each object instantiated. This can save substantial amounts of mem-
ory.

Note:
Before doing your lab exercises run the examples.

Exercise:
Question 1: Write a C++ class BankAccount having private data members int Ac-
count_no and double balance. It must contain constructor for initializing(Account_no
and balance) objects and member functions for setBalance, setAccount_no, getBal-
ance, getAccount_no, display , withdraw and deposit function to decrement and
increment the amount to the balance. Call these functions for two account holders.

Question 2: Write a program to find maximum out of two numbers using friend
function and also note one number is a member of one class and other number is
member of some other class. By using set function set values of data members.
1 Lab 8:Friend Function & Classes, This Pointer, and static

Question 3: Write a C++ program to create three objects for a class named pntr_obj
with data members such as roll_no & name . Create a member function set_data()
for setting the data values and print() member function to print which object has
invoked it using â A˘ Ÿ thisâ A˘ Z´ pointer .
Chapter 9

Lab 9:Operator Overloading

In C++ the overloading principle applies not only to functions, but to operators too.
That is, of operators can be extended to work not just with built-in types but also
classes. A programmer can provide his or her own operator to a class by overload-
ing the built-in operator to perform some specific computation when the operator
is used on objects of that class. Is operator overloading really useful in real world
implementations? It certainlly can be, making it very easy to write code that feels
natural (we’ll see some examples soon). On the other hand, operator overloading,
like any advanced C++ feature, makes the language more complicated. In addition,
operators tend to have very specific meaning, and most programmers don’t expect
operators to do a lot of work, so overloading operators can be abused to make code
unreadable. But we won’t do that.

An Example of Operator Overloading


Complex a(1.2,1.3); //this class is used to represent complex numbers
Complex b(2.1,3); //notice the construction taking 2 parameters for the real and
imaginary part
Complex c = a+b; //for this to work the addition operator must be overloaded

The addition without having overloaded operator + could look like this:

Complex c = a.Add(b);

This piece of code is not as readable as the first example though–we’re dealing with
numbers, so doing addition should be natural. (In contrast to cases when program-
mers abuse this technique, when the concept represented by the class is not
related to the operator–ike using + and - to add and remove elements from a data
structure. In this cases operator overloading is a bad idea, creating confusion.) In
order to al- low operations like Complex c = a+b, in above code we overload the "+"
operator. The overloading syntax is quite simple, similar to function overloading,
the keyword

111
1 Lab 9:Operator

operator must be followed by the operator we want to overload:

1 c l a s s Complex
2
3 {
4 public :
5 Complex ( double re , double im )
6 : r e a l ( re ) , imag ( im )
7 {};
8 Complex operator +( const Complex& other ) ;
9 Complex operator =( const Complex& other ) ;
10 pr iva t e :
11 double r e a l ;
12 double imag ;
13 };
14 Complex Complex : : operator +( const Complex& other )
15
16 {
17 double r e s u l t _ r e a l = r e a l + other . r e a l ;
18
19 double r e s u l t _ i m a g i n a r y = imag + other . imag ;
20
21 return Complex ( r e s u l t _r e a l , result_imaginary ) ;}

The assignment operator can be overloaded similarly. Notice that we did not have
to call any accessor functions in order to get the real and imaginary parts from the
parameter other since the overloaded operator is a member of the class and has
full access to all private data. Alternatively, we could have defined the addition
operator globally and called a member to do the actual work. In that case, we’d also
have to make the method a friend of the class, or use an accessor method to get at
the private data:

1 f r i e n d Complex operator +( Complex ) ;


2 Complex operator +( const Complex &num1 , const Complex &num2 )
3 {
4
5 double r e s u l t _ r e a l = num1 . r e a l + num2 . r e a l ;
6
7 double r e s u l t _ i m a g i n a r y = num1 . imag + num2 . imag ; return Complex ( r e s u l t _r e a l
, result_imaginary ) ;
8
9 }

Why would you do this? when the operator is a class member, the first object in the
expression must be of that particular type. It’s as if you were writing:

Complex a( 1, 2 );
Complex a( 2, 2 );
Complex c = a.operator=( b );
1

when it’s a global function, the implicit or user-defined conversion can allow the
operator to act even if the first operand is not exactly of the same type:

Complex c = 2+b; //if the integer 2 can be converted by the Complex class, this
expression is valid By the way, the number of operands to a function is fixed; that is,
a binary operator takes two operands, a unary only one, and you can’t change it. The
same is true for the precedence of operators too; for example the multiplication oper-
ator is called before addition. There are some operators that need the first operand to
be assignable, such as : operator=, operator(), operator[] and operator->, so their use
is restricted just as member functions(non-static), they can’t be overloaded globally.
The operator=, operator& and operator, (sequencing) have already defined meanings
by default for all objects, but their meanings can be changed by overloading or erased
by making them private. Another intuitive meaning of the "+" operator from the STL
string class which is overloaded to do concatenation:

1 s t r i n g p r e f i x ( " de " ) ;
2 s t r i n g word( " composed " ) ;
3 s t r i n g composed = p r e f i x +word ;

Using "+" to concatenate is also allowed in Java, but note that this is not extensible
to other classes, and it’s not a user defined behavior. Almost all operators can be
overloaded in C++:

Table 9.1: Add caption


+ - * / % &ˆ |
! , = =
++ – « » == != && ||
+= -= /= %= =ˆ & = |= *=
«= »= [] ( ) -> ->* new delete

The only operators that can’t be overloaded are the operators for scope resolution
(::), member selection (.), and member selection through a pointer to a function(.*).
Overloading assumes you specify a behavior for an operator that acts on a user de-
fined type and it can’t be used just with general pointers. The standard behavior of
operators for built-in (primitive) types cannot be changed by overloading, that is, you
can’t overload operator+(int,int). The logic(boolean) operators have by the default a
short-circuiting way of acting in expressions with multiple boolean operations. This
means that the expression:

if(a && b&& c) will not evaluate all three operations and will stop after a false one
is found. This behavior does not
1 Lab 9:Operator

apply to operators that are overloaded by the programmer. Even the simplest C+
+ application, like a "hello world" program, is using overloaded operators. This is
due to the use of this technique almost everywhere in the standard library (STL).
Actually the most basic operations in C++ are done with overloaded operators, the
IO(input/output) operators are overloaded versions of shift operators(«, »). Their
use comes naturally to many beginning programmers, but their implementation is
not straightforward. However a general format for overloading the input/output
operators must be known by any C++ developer. We will apply this general form to
manage the input/output for our Complex class:

1 f r i e n d ostream &operator <<( ostream &out , Complex c ) //output {


2
3 out <<" r e a l part : " <<real <<"\n" ;
4 out <<" imag part : " <<imag<<"\n" ;
5 return out ;
6 }
7 f r i e n d istream &operator >>( istream &in , Complex &c ) //input
8 { cout <<" enter r e a l part :\ n" ;
9 in >>c . r e a l ;
10 cout <<" enter imag part : \n" ;
11
12 in >>c . imag ;
13 return in ; }

Notice the use of the friend keyword in order to access the private members in the
above implementations. The main distinction between them is that the operator» may
encounter unexpected errors for incorrect input, which will make it fail sometimes
because we haven’t handled the errors correctly. A important trick that can be seen
in this general way of overloading IO is the returning reference for
istream/ostream which is needed in order to use them in a recursive manner:

1 Complex a ( 2 , 3 ) ;
2 Complex b ( 5 . 3 , 6 ) ;
3
4 cout <<a<<b ;

Note:

Before doing your lab exercises run the examples.


1

Exercise:
Q 1: Write a program to make a class of Rational numbers with data members numer-
ator and denominator and member functions getdata() "to get data", showdata()"to
display data", adddata() "add the data of two fractions" and operator+() "to add two
objects such that numerator is added with numerator and denominator with denom-
inator".

Q2: Write a program to make a class Distance with data members meters and kilo-
meters, and member function getdata() "get data for distances", showdata()"display
data for distances’, operator++()"increments meters=meters+100, if meter exceeds
than 1000meters then increment kilometers by 1 and decrement meters by 1000 ",
and operator - -()"work in the same manner like ++ but operation is totally oppo-
site".
Q3: Write a program to make a class of Complex numbers with data members as
real and imaginary numbers and getreal(), getimg() and Show() to get real numbers
, imaginary numbers and to show data respectively and operator+()"subtract two
objects", operator-()"add two objects", operator/()"multiply two objects", and opera-
tor*() "divide first object by second object".
1 Lab 9:Operator
Chapter 10

Lab 10:Inheritance

One of the most important concepts in object-oriented programming is that of inher-


itance. Inheritance allows us to define a class in terms of another class, which makes
it easier to create and maintain an application. This also provides an opportunity to
reuse the code functionality and fast implementation time. When creating a class,
instead of writing completely new data members and member functions, the pro-
grammer can designate that the new class should inherit the members of an existing
class. This existing class is called the base class, and the new class is referred to as
the derived class.

The idea of inheritance implements the is a relationship. For example, mammal IS-
A animal, dog IS-A mammal hence dog IS-A animal as well and so on.

Base & Derived Classes:


A class can be derived from more than one classes, which means it can inherit data
and functions from multiple base classes. To define a derived class, we use a class
derivation list to specify the base class(es). A class derivation list names one or
more base classes and has the form:

class derived-class: access-specifier base class

Where access-specifier is one of public, protected, or private, and base-class is the


name of a previously defined class. If the access-specifier is not used, then it is pri-
vate by default.

Consider a base class Shape and its derived class Rectangle as follows:

1 # include <iostream >


2
3 using namespace std ;
4

117
1 Lab

5 //Base c l a s s c l a s s Shape
6
7 {
8 public :
9 void setWidth ( i n t w)
10 {
11
width = w;
12
13 }
14
void set Height ( i n t h )
{
15
height = h ;
16
}
17
18
pr ot e ct e d : i n t width ; i n t height ;
19
};
20
21
//Derived c l a s s
22
c l a s s Rectangle : public Shape
23
{
24 public :
25
26 i n t get Area ( )
27
28
{
29
30 return ( width ∗ height ) ;
31 }
32 };
33
34 i n t main ( void )
35 {
36 Rectangle Rect ;
37
38 Rect . setWidth ( 5 ) ; Rect . set Height ( 7 ) ;
39
40 // P r i n t the area of the o b j e c t .
41 cout << " Total area : " << Rect . getArea ( ) << endl ;
42
43 return 0;
44 }
45

When the above code is compiled and executed, it produces following

result: Total area: 35

Access Control and Inheritance:


A derived class can access all the non-private members of its base class. Thus base-
class members that should not be accessible to the member functions of derived
1

classes should be declared private in the base class.

We can summarize the different access types according to who can access them in
the following way:

Table 10.1: Add caption


Access public protected private

Same class yes yes yes

Derived classes yes yes no

Outside classes yes no no

A derived class inherits all base class methods with the following exceptions:
• Constructors, destructors and copy constructors of the base class.
• Overloaded operators of the base class.
• The friend functions of the base class.

Type of Inheritance:
When deriving a class from a base class, the base class may be inherited through
public, protected or private inheritance. The type of inheritance is specified by the
access-specifier as explained above.

We hardly use protected or private inheritance but public inheritance is commonly


used. While using different type of inheritance, following rules are applied:

• Public Inheritance: When deriving a class from a public base class, public mem-
bers of the base class become public members of the derived class and protected
members of the base class become protected members of the derived class. A base
class’s private members are never accessible directly from a derived class, but can be
accessed through calls to the public and protected members of the base class.
1 Lab

• Protected Inheritance: When deriving from a protected base class, public and pro-
tected members of the base class become protected members of the derived class.

• Private Inheritance: When deriving from a private base class, public and protected
members of the base class become private members of the derived class.

Multiple Inheritances:
A C++ class can inherit members from more than one class and here is the extended
syntax:

class derived-class: access baseA, access baseB....

Where access is one of public, protected, or private and would be given for every
base class and they will be separated by comma as shown above. Let us try the fol-
lowing example:

1 # include <iostream > using namespace std ;


2 //Base c l a s s Shape c l a s s Shape
3
4 {
5 public :
6 void setWidth ( i n t w)
7
{
8
width = w;
}
9
void set Height ( i n t h )
10
{
11
height = h ;
12 }
13
14
pr ot e ct e d : i n t width ; i n t height ;
15 };
16
17 //Base c l a s s Paint Cost c l a s s Paint Cost
18
19
{
20 public :
21 i n t get Cost ( i n t area )
22 {
23
24
25
26
27 return area ∗ 7 0 ;
28 }
29
1

30 };
31
32 // Derived c l a s s
33 c l a s s Rectangle : public Shape , public Paint Cost
34 {
35 public :
36
i n t get Area ( )
37
38 {
39 return ( width ∗ height ) ;
40 }
41 };
42
43 i n t main ( void )
44 {
45
46 Rectangle Rect ; i n t area ;
47
48 Rect . setWidth ( 5 ) ; Rect . set Height ( 7 ) ;
49
50 area = Rect . getArea ( ) ;
51
52 // P r i n t the area of the o b j e c t .
53 cout << " Total area : " << Rect . get Area ( ) << endl ;
54
55 // P r i n t the t o t a l c o s t of pain tin g
56 cout << " Total paint c o s t : $ " << Rect . get Cost ( area ) << endl ; return 0 ;
57 }
58
59
60
61
62

When the above code is compiled and executed, it produces following result:

Total area: 35

Total paint cost: $2450


Note:
Before doing your lab exercises run the examples.
1 Lab

Exercise:
Question 1: Define a class Student as a base class with data members as admissionNo,
Name, age and address as protected type and getStudent function for setting values
for these data members. These members and functions are common to both
derived classes. Make two derived classes of Student class as undergraduate and
graduate student each containing data member degree_program "in which student is
enrolled" and member functions getdegree "set degree_program" and show
"display whole information". Degree in which student is enrolled and display the
whole information of graduate and undergraduate student like this

Figure 10.1:

Question 2: By using multiple inheritance, make a student class representing


student with data member roll_no and two member functions get_roll_no to get
and display_roll_no to display roll number of student. A test class (derived class of
student) representing the scores of the student in two subjects and sports class(derive
class of stu) representing the score in sports. The sports and test class should be
inherited by a result class having the functionality to add the scores of two subjects
and sports score an then display the final result for students.
Chapter 11

Lab 11:Introduction to
Polymorphism and Abstract Base
Classes

Polymorphism
Polymorphism is a mechanism that allows you to implement a function in different
ways. Polymorphism is by far the most important and widely used concept in
object oriented programming.

Pointers to base class


We have seen that it is possible to derive a class from a base class and that we can
add functionality to member functions.

One of the features of derived classes is that a pointer to a derived class is type-
compatible with a pointer to its base class. Polymorphism takes advantage of this
feature.

Letâ A˘ Z´ s take a look at an example of a base class and derived classes:

1 # include <iostream >


2
3 using namespace std ;
4
5 c l a s s CPolygon
6
7 {
8 pr o te c te d :
9 i n t width , height ;
10 public :
11 void setup ( i n t f i r s t , i n t second )

123
1 Lab 11:Introduction to Polymorphism and Abstract Base

12
13 {
14 width= f i r s t ;
15 height= second ;
16 }
17
};
18
19
c l a s s CRectangle : public CPolygon
20
21 {
22
public :
i n t area ( )
23
24
25
{
26 return ( width ∗ height ) ;
27 }
28 };
29
30 c l a s s CTriangle : public CPolygon
31 {
32 public :
33
i n t area ( )
34
{
35
36 return ( width ∗ height / 2 ) ;
37 }
38 };
39
40 i n t main ( )
41
42 {
43 CRectangle r e c t a n gl e ; CTriangle t r i a n g l e ;
44 CPolygon ∗ ptr_polygon1 = &r e c t a n gl e ; CPolygon ∗ ptr_polygon2 = &t r i a n g l e ;
45
46
47
48
49
50 ptr_polygon1 −>setup ( 2 , 2 ) ;
51 ptr_polygon2 −>setup ( 2 , 2 ) ;
52 cout << r e c t a n gl e . area ( ) << endl ; cout << t r i a n g l e . area ( ) << endl ;
53
54
55
56 return 0;
57 }

As you can see, we create two pointers (ptr_polygon1 and ptr_polygon2) that point
to the objects of class CPolygon. Then we assign to these pointers the address of
(us- ing the reference ampersand sign) the objects rectangle and triangle. Both
rectangle and triangle are objects of classes derived from CPolygon.

In the cout statement we use the objects rectangle and triangle instead of the pointers
1

ptr_polygon1 and ptr_polygon2. We do this because ptr_polygon1 and


ptr_polygon2 are of the type CPolygon. This means we can only use the pointers to
refer to mem- bers that CRectangle and CTriangle inherit from Cpolygon.

If we want to use the pointers to class CPolygon then area() should be declared
in the class CPolygon and not only in the derived classes CRectangle and Ctriangle.

The problem is that we use different versions of area() in the derived classes
â A˘ S¸ CRectangle and Ctriangle â A˘ S¸ so we canâ A˘ Z´ t implement one version of
area() in the base class CPolygon. (If they were the same we had no problem.)

We can fix this by using virtual members.

Virtual Members
A virtual member is a member of a base class that we can redefine in its derived
classes. To declare a member as virtual we must use the keyword virtual.

Letâ A˘ Z´ s change our previous example:

1 # include <iostream >


2 using namespace std ;
3
4 c l a s s CPolygon
5
6 {
7 pr o te c te d :
8 i n t width , height ;
9
10 public :
11 void setup ( i n t f i r s t , i n t second )
12 {
13 width= f i r s t ;
14 height= second ;
15 }
16
17 v i r t u a l i n t area ( )
18 {
19 return ( 0 ) ;
20 }
21 };
22
23 c l a s s CRectangle : public CPolygon
24
25 {
26 public :
1 Lab 11:Introduction to Polymorphism and Abstract Base

27 i n t area ( )
28 {
29 return ( width ∗ height ) ;
30 }
31 };
32
33 c l a s s CTriangle : public CPolygon
34 {
35 public :
36 i n t area ( )
37
{
38
39 return ( width ∗ height / 2 ) ;
40 }
41
42 };
43
44 i n t main ( )
45 {
46 CRectangle r e c t a n gl e ;
47
48 CTriangle t r i a n g l e ; CPolygon polygon ;
49
50
51 CPolygon ∗ ptr_polygon1 = &r e c t a n gl e ;
52 CPolygon ∗ ptr_polygon2 = &t r i a n g l e ;
53 CPolygon ∗ ptr_polygon3 = &polygon ;
54
55 ptr_polygon1 −>setup ( 2 , 2 ) ;
56 ptr_polygon2 −>setup ( 2 , 2 ) ;
57 ptr_polygon3 −>setup ( 2 , 2 ) ;
58
cout << ptr_polygon1 −>area
59 ( ) << endl ;
60
61 cout << ptr_polygon2 −>area ( ) << endl ;
62 cout << ptr_polygon3 −>area ( ) << endl ;
63 return 0 ;
64 }
65

Because of the change â A˘ S¸ adding area() as a virtual member of CPolygon


â A˘ S¸ now all the three classes have all the same members (width, height, setup() and
area().)

A class that declares or inherits a virtual function is called a polymorphic class.

Abstract Base Classes:


At the design level, an abstract base class (ABC) corresponds to an abstract concept.
For instance: if you ask to draw a shape, I will probably ask what kind of shape.
1

The term "shape" is an abstract concept, it could be a circle, a square, etc, etc. You
could say in C++ that class CShape is an abstract base class (ABC) and class circle
(etc) could be a derived class.

As we look at the C++ language we could say that an abstract base class has one
or more pure virtual member functions.

In the example above we put an implementation (return (0);) in the virtual mem-
ber function area(). If we want to change it into a pure virtual member function we
use =0; instead of the return (0). So the class will look like this:

1 c l a s s CPolygon
2
3 {
4
5 pr o te c te d :
6 i n t width , height ;
7 public :
8
9 void setup ( i n t f i r s t , i n t second )
10 {
11 width= f i r s t ;
12 height= second ;
13 }
14
15 v i r t u a l i n t area ( ) = 0 ;
16 };

This pure virtual function area() makes CPolygon an abstract base class. But you
have to remember the following: by adding a pure virtual member to the base
class, you are forced to also add the member to any derived class.

So our example should now look like this:

1 # include <iostream >


2
3 using namespace std ;
4
5 c l a s s CPolygon
6 {
7 pr o te c te d :
8
9 i n t width , height ;
10 public :
11 void setup ( i n t f i r s t , i n t second )
12 {
13 width= f i r s t ;
14
15 height= second ;
1 Lab 11:Introduction to Polymorphism and Abstract Base

16 }
17 v i r t u a l i n t area ( ) = 0 ;
18 };
19
20 c l a s s CRectangle : public CPolygon
21 {
22
public :
23
i n t area ( void )
{
24
25
26 return ( width ∗ height ) ;
27 }
28 };
29 c l a s s CTriangle : public CPolygon
30 {
31
public :
i n t area ( void )
32
{
33
34 return ( width ∗ height / 2 ) ;
35 }
36
37 };
38
39 i n t main ( )
40 {
41 CRectangle r e c t a n gl e ;
42
43 CTriangle triangle ;
44
45 CPolygon ∗ ptr_polygon1 = &r e c t a n gl e ;
46 CPolygon ∗ ptr_polygon2 = &t r i a n g l e ;
47
48 ptr_polygon1 −>setup ( 2 , 2 ) ;
49 ptr_polygon2 −>setup ( 2 , 2 ) ;
50
51 cout << ptr_polygon1 −>area ( ) << endl ;
52 cout << ptr_polygon2 −>area ( ) << endl ;
53 return 0 ;
54
55
56 }

Note:
there is also an extra void in the derived classes CRectangle and CTriangle.

Using a unique type of pointer (CPolygon*) we can point to objects of different but
related classes. We can make use of that. For instance: we could implement an extra
function member in the abstract base class CPolygon that can print the result of the
area() function. (Remember that CPolygon itself has no implementation for the func-
tion area() and still we can use it, isnâ A˘ Z´ t it cool.) After implementation of
such a
1

function the example will look like this:

1 # include <iostream > using namespace std ;


2 c l a s s CPolygon
3 {
4 pr ot e ct e d :
5
i n t width , height ; public :
6
7
void setup ( i n t f i r s t , i n t second )
8
{
width= f i r s t ;
9
height= second ;
10
}
11
12
v i r t u a l i n t area ( void ) = 0 ; void onscreen ( void )
13
{
14
15
16
17
18
19
20 cout << t his −>area ( ) << endl ;
21 }
22
23 };
24 c l a s s CRectangle : public CPolygon
25
26 {
27 public :
28 i n t area ( void )
29
{
30 return ( width ∗ height ) ;
31 }
32 };
33
34 c l a s s CTriangle : public CPolygon
35
36 {
37 public :
38 i n t area ( void )
39
40 {
41 return ( width ∗ height / 2 ) ;
42 }
43 };
44
45 i n t main ( )
46 {
47 CRectangle r e c t a n gl e ; CTriangle t r i a n g l e ;
48
49 CPolygon ∗ ptr_polygon1 = &r e c t a n gl e ;
50
51
1 Lab 11:Introduction to Polymorphism and Abstract Base

52 CPolygon ∗ ptr_polygon2 = &t r i a n g l e ;


53
54 ptr_polygon1 −>setup ( 2 , 2 ) ;
55 ptr_polygon2 −>setup ( 2 , 2 ) ;
56
ptr_polygon1 −>onscreen ( ) ; ptr_polygon2 −>onscreen ( ) ; return 0 ;
57
58
59
60
61
62
63 }

Note:
Before doing your lab exercises run the examples.

Exercise:
Question 1: By using the concept of virtual function, create a class shape with data
members length and breadth as protected and these data members are initialized
using class constructor. Shape class has two virtual member functions area() "calcu-
lates area"and display() "display calculated area". Now derive three classes rectangle,
circle and trapezoidal from shape class. Each class has its own area() and display()
member functions to calculate area and display. Only rectangle class use data mem-
bers of shape class while circle and trapezoidal has its own data members. Make
three pointers of base class and object of each remaining classes, pointers pointing to
each class object.
Hint:
Circle Area: A=ÏA˘ r2ˆ
Trapezoidal Area: A=(1â A˛Dˇ 2*(lengthside1+lengthside2))*height;
Question 2:
By implementing pure virtual function, make a class student with data members
name and department as protected type and two pure virtual member functions
get_data() "to input the student record"and show_data() "display student record".
Now derive three classes Medical, Engineering, and Science from student class with
its own member functions of get_data() "to input the student record" and show_data()
"display student record" while using data members of student class. Now in main
portion of your program create an array of pointers of base class having size three
and assign to each index remaining class objects addresses. By using for loop
iterate
1

array and take input then again display records using for loop. Hint: Donâ A˘ Z´ t
need to pass name and department as argument to functions.
1 Lab 11:Introduction to Polymorphism and Abstract Base
Chapter 12

Lab 12:File Handling in C++

Input/output with files

C++ provides the following classes to perform output and input of characters to/from
files:
• ofstream: Stream class to write on files
• ifstream: Stream class to read from files
• fstream: Stream class to both read and write from/to files.

These classes are derived directly or indirectly from the classes istream, and ostream.
We have already used objects whose types were these classes: cin is an object of
class istream and cout is an object of class ostream. Therfore, we have already been
using classes that are related to our file streams. And in fact, we can use our file
streams the same way we are already used to use cin and cout, with the only differ-
ence that we have to associate these streams with physical files. Let’s see an example:

1 // b a s i c f i l e o pe r ati o ns # include <iostream > # include <fstream > using


namespace std ; i n t main ( )
2 {
3
4 ofstream myfile ; myfile . open ( " example . t x t " ) ;
5
6 myfile << " Writing t h i s to a f i l e .\ n" ; myfile . c l o s e ( ) ;
7
8 return 0 ;
9 }

This code creates a file called example.txt and inserts a sentence into it in the same
way we are used to do with cout, but using the file stream myfile instead. But let’s
go step by step:

133
1 Lab 12:File Handling in

Open a file
The first operation generally performed on an object of one of these classes is to
associate it to a real file. This procedure is known as to open a file. An open file
is represented within a program by a stream object (an instantiation of one of these
classes, in the previous example this was myfile) and any input or output operation
performed on this stream object will be applied to the physical file associated to it.

In order to open a file with a stream object we use its member function open():

open (filename, mode);

Where filename is a null-terminated character sequence of type const char (the same
type that string literals have) representing the name of the file to be opened, and
mode is an optional parameter with a combination of the following flags:

Figure 12.1:

All these flags can be combined using the bitwise operator OR (|). For example,
if we want to open the file example.bin in binary mode to add data we could do it
by the following call to member function open():
ofstream myfile;
myfile.open ("example.bin", ios::out | ios::app | ios::binary);

Each one of the open() member functions of the classes ofstream, ifstream and
fstream has a default mode that is used if the file is opened without a second ar-
gument

For ifstream and ofstream classes, ios::in and ios::out are automatically and respec-
tively assumed, even if a mode that does not include them is passed as second argu-
ment to the open() member function.

The default value is only applied if the function is called without specifying any
value for the mode parameter. If the function is called with any value in that
param- eter the default mode is overridden, not combined.
1

File streams opened in binary mode perform input and output operations indepen-
dently of any format considerations. Non-binary files are known as text files, and
some translations may occur due to formatting of some special characters (like new-
line and carriage return characters).

Since the first task that is performed on a file stream object is generally to open
a file, these three classes include a constructor that automatically calls the open()
member function and has the exact same parameters as this member. Therefore, we
could also have declared the previous myfile object and conducted the same opening
operation in our previous example by writing:
ofstream myfile ("example.bin", ios::out | ios::app | ios::binary);

Combining object construction and stream opening in a single statement. Both forms
to open a file are valid and equivalent.
To check if a file stream was successful opening a file, you can do it by calling to
member is_open() with no arguments. This member function returns a bool value of
true in the case that indeed the stream object is associated with an open file, or false
otherwise:

if (myfile.is_open()) /* ok, proceed with output */

This will open the file without destroying the current contents and allow you to
append new data. When opening files, be very careful not to use them if the file
could not be opened. This can be tested for very easily:

1 i f s t r e a m a _ f i l e ( " example . t x t " ) ;


2
3 i f ( ! a _ f i l e . is_open ( ) ) {
4 // The f i l e could not be opened
5 }
6
7 else {
8
9 // Sa fe ly use the f i l e stream

Closing a file
When we are finished with our input and output operations on a file we shall close
it so that its resources become available again. In order to do that we have to call the
stream’s member function close(). This member function takes no parameters, and
what it does is to flush the associated buffers and close the file:

myfile.close();
1 Lab 12:File Handling in

Once this member function is called, the stream object can be used to open another
file, and the file is available again to be opened by other processes. In case that an
object is destructed while still associated with an open file, the destructor automati-
cally calls the member function close().

Text files
Text file streams are those where we do not include the ios::binary flag in their open-
ing mode. These files are designed to store text and thus all values that we input
or output from/to them can suffer some formatting transformations, which do not
necessarily correspond to their literal binary value.

Data output operations on text files are performed in the same way we operated
with cout:

1 // writing on a t e x t f i l e
2 # include <iostream > # include <fstream > using namespace std ; i n t main ( ) {
3
4 ofstream myfile ( " example . t x t " ) ; i f ( myfile . is_open ( ) )
5
6 {
7
8 myfile << " This i s a l i n e .\ n" ;
9 myfile << " This i s another l i n e .\ n" ;
10 myfile . c l o s e ( ) ;
11 }
12 e l s e cout << " Unable to open f i l e " ;
13 return 0 ;
14 }

[file example.txt]
This is a line.
This is another line.

Data input from a file can also be performed in the same way
that we did with cin:

1 // reading a t e x t f i l e
2 # include <iostream > # include <fstream >
1

3 # include <s t r ing > using namespace std


4 ; i n t main ( ) {
5
6 string line ;
7
8 i f s t r e a m myfile ( " example . t x t " ) ; if ( myfile . is_open ( ) )
9 {
10 while ( ! myfile . eof ( ) )
11 {
12
13 g e t l i n e ( myfile , l i n e ) ; cout << l i n e << endl ;
14 }
15 myfile . c l o s e ( ) ;
16 }
17
18 e l s e cout << " Unable to open f i l e " ; return 0;
19 }

This is a line.
This is another line.

This last example reads a text file and prints out its content on the screen. Notice
how we have used a new member function, called eof() that returns true in the case
that the end of the file has been reached. We have created a while loop that finishes
when indeed myfile.eof() becomes true (i.e., the end of the file has been reached).

Checking state flags


In addition to eof(), which checks if the end of file has been reached, other member
functions exist to check the state of a stream (all of them return a bool value):

bad()
Returns true if a reading or writing operation fails. For example in the case that we
try to write to a file that is not open for writing or if the device where we try to write
has no space left.

fail()
Returns true in the same cases as bad(), but also in the case that a format error hap-
pens, like when an alphabetical character is extracted when we are trying to read an
integer number.
1 Lab 12:File Handling in

eof()

Returns true if a file open for reading has reached the end.

good()

It is the most generic state flag: it returns false in the same cases in which calling any
of the previous functions would return true.

In order to reset the state flags checked by any of these member functions we have
just seen we can use the member function clear(), which takes no parameters.

get and put stream pointers

All i/o streams objects have, at least, one internal stream pointer:

ifstream, like istream, has a pointer known as the get pointer that points to the
element to be read in the next input operation.
ofstream, like ostream, has a pointer known as the put pointer that points to the
location where the next element has to be written.
Finally, fstream, inherits both, the get and the put pointers, from iostream (which is
itself derived from both istream and ostream).

These internal stream pointers that point to the reading or writing locations within a
stream can be manipulated using the following member functions:

tellg() and tellp()

These two member functions have no parameters and return a value of the member
type pos_type, which is an integer data type representing the current position of the
get stream pointer (in the case of tellg) or the put stream pointer (in the case of tellp).
1

seekg() and seekp()


These functions allow us to change the position of the get and put stream pointers.
Both functions are overloaded with two different prototypes. The first prototype is:

seekg ( position );

seekp ( position );
Using this prototype the stream pointer is changed to the absolute position position
(counting from the beginning of the file). The type for this parameter is the same as
the one returned by functions tellg and tellp: the member type pos_type, which is an
integer value. The other prototype for these functions is:

seekg ( offset, direction );

seekp ( offset, direction );


Using this prototype, the position of the get or put pointer is set to an offset value
relative to some specific point determined by the parameter direction. offset is of the
member type off_type, which is also an integer type.

And direction is of type seekdir, which is an enumerated type (enum) that deter-
mines the point from where offset is counted from, and that can take any of the
following values:

Exercise:
Lab-12 Task: Question1: Write a program that creates two files file1.dat and file2.dat,
input same data to both files and show data of both files. Now compare data of
both files and display a message "both files have same content". Now modify data
in file2 just by appending some more content at the end of file, again show data and
compare them and display message "files have different content".

Question2:
1 Lab 12:File Handling in

Make a class rubric with data members regno(RegNo. of student), clearity(value


should be nonnegative and less than or equal to 2), completeness(value should be
nonnegative and less than or equal to 3), accuracy(value should be non-negative and
less than or equal to 3), time(value should be nonnegative and less than or equal to 2),
and total_marks. Class has member function input() that inputs data for regno, clear-
ity, completeness, accuracy, time, and total_marks=clearity+completeness+accuracy+time.
Class has function output()" output data to student.txt" and show()"show content of
student.txt (format is given below)". Create an object and enter data for any three
CS102 student store their data in student.txt and display them.

You might also like