CPP
CPP
73
3.1................................................Intro
duction................................................................ w.................................................................................. 73
3.2.......................................................................................................... Data Encapsulation and Abstraction
73
3.3..........................................................................................................Inheritance—Derived Classes
78
3.4..........................................................................................................Polymorphism-Operator Overloadin
81
3.5..........................................................................................................Friend Functions
84
3.6..........................................................................................................Polymorphism—Virtual Functions
87
3.7..........................................................................................................Generic Classes—Class Templates
90
3.8..........................................................................................................Exception Handling
92
3.9..........................................................................................................Streams Computation
95
Review Questions............................................................................................................................. 99
4.10.......................................................................................................Qualifiers
109
4.11.......................................................................................................Arithmetic Operators
112
4.12.......................................................................................................Relational Operators
115
4.13.......................................................................................................Logical Operators
118
4.14.......................................................................................................Pit-wise Operators
120
4.15.......................................................................................................Compound Assignment Operators
124
4.16.......................................................................................................Increment and Decrement Operators
125
4.17.......................................................................................................Conditional Operator (Ternary Oper
126
4.18.......................................................................................................Special Operators
128
4.19.......................................................................................................typedef Statement
128
4.20.......................................................................................................Promotion and Type Conversion
129
4.21.......................................................................................................Constants
131
4.22.......................................................................................................Declaring Symbolic Constants-Liter
134
4.23.......................................................................................................Enumerated Data Types
136
4 24 Macro Functions .......................................................................................................................... 138
4.25 Operator Precedence and Associativity......................................................................................... 140
Review Questions......................................................................................................................... 142
5J___Introduction.............
.....................................................................................
............143
5.2 Statements and Block...................................................................................................................... 143
13 if Statement...................................................................................................................................... 144
S4 if-p.lse Statement............................................................................................................................ 146
S S N«ted if-else Statements...............................................................................................................148
return temp;
)
// it is just a friend function, it is not a member of
counter classes ostream & operator « ( ostream &
Out, counter & counter )
{
/
/
d
i
s
p
l
a
y
a
l
Copyrighted material
sdv Contents
i
n
t
e
r
n
a
l
d
a
t
a
o
f
c
o
u
n
t
e
r
c
l
a
s
s
c
o
u
t
c
o
u
n
t
e
r
.
v
a
l
u
e
;
//
retu
rn
Copyrighted material
sdv Contents
out
put
stre
am
Out
for
cas
cad
ing
pur
pos
e
retu
rn
Out
;
)
v
o
i
d
m
a
i
n
O
{
counter counterl;. // calls no
argument constructor
counter counter2 = 1 ; // calls 1 argument
constructor cout << "counterl initially = " «
counterl « endl; cout « "counter2 initially = " «
counter2 « endl; // increment counter ♦♦counterl;
counter2++;
cout « "counterl on increment = " « counterl «
endl; cout << "counter2 on increment = " «
counter2 « endl; // decrement counter --counter1;
counter2--;
cout « "counterl on decrement = " « counterl «
endl;
cout « "counter2 on decrement = " « counter2 «
endl;
counter counter3; // calls no
argument constructor
counter3 = counterl + counter2; // calls
operator*(counter) cout « "counter3 =
"counterl+counter2 = " << counter3;
)
Run
c
o
u
n
Copyrighted material
sdv Contents
t
e
r
l
i
n
i
t
i
a
l
l
y
c
o
u
n
t
e
r
2
i
n
i
t
i
a
l
l
y
c
o
u
n
t
e
r
l
o
n
i
n
c
Copyrighted material
sdv Contents
r
e
m
e
n
t
c
o
u
n
t
e
r
2
o
n
i
n
c
r
e
m
e
n
t
c
o
u
n
t
e
r
l
o
n
d
e
c
r
e
m
e
n
Copyrighted material
sdv Contents
c
o
u
n
t
e
r
2
o
n
d
e
c
r
e
m
e
n
t
c
o
u
n
t
e
r
3
c
o
u
n
t
e
r
l
+
c
o
u
n
t
Copyrighted material
sdv Contents
e
r
2
c
o
u
n
t
e
r
l
;
i
n
s
t
e
a
d
o
f
u
s
i
n
g
t
h
e
Copyrighted material
sdv Contents
s
t
a
t
e
m
e
n
t
cout << counter.GetCounter(); This is the
same as the use of the stream operator to display the
contents of variables of standard data type. The
operator member function
ostream & operator « ( ostream & Out,
counter & counter ) ;
defined in the counter class displays the contents of
the objects of the counter class (see Figure 3.4). The
stream classes, istream and ostream are declared in the
iostream.h header file.
Copyrighted material
Chapter 3: C++at a Glance 91
c
l
a
s
s
m
y
c
l
a
s
s
{
int arr[5] ;
};
The template declaration of the vector class is
illustrated in the program vector. cpp. It has a data
member which is a pointer to an array of generic type
T. The type T can be changed to int, float, etc.,
depending on the type of object to be created.
Copyrighted material
sdv Contents
#include <iostream.h>
template <class T>
class vector
{
T * v; // changes to int *v,
float *v, etc.
int size; // size of vector v
public:
v
e
c
t
o
r
(
i
n
t
v
e
c
t
o
r
_
s
i
z
e
{
size = vector_size;
v * new T[ vector_size ]; //e.g., v=new
int[ size ],if T is int
)
-
v
e
c
t
o
r
(
)
(
delete v;
)
T & elemi int i )
{
if( i >- size )
Copyrighted material
sdv Contents
c
o
u
t
e
n
d
l
"
E
r
r
o
r
:
O
u
t
o
f
R
a
n
g
e
*
;
r
e
t
u
r
n
v
[
i
]
;
)
void show();
);
t
e
m
p
l
a
t
e
<
c
Copyrighted material
sdv Contents
l
a
s
s
T
>
v
o
i
d
v
e
c
t
o
r
<
T
>
s
h
o
w
(
)
{
for(
i
n
t
0
;
<
s
i
z
e
;
i
+
+
Copyrighted material
sdv Contents
c
o
u
t
e
l
e
m
(
"
;
>
v
o
i
d
m
a
i
n
(
)
{
int i;
v
e
c
t
o
r
<
i
n
t
>
i
n
t
_
v
e
c
t
(
Copyrighted material
sdv Contents
)
;
v
e
c
t
o
r
<
f
l
o
a
t
>
f
l
o
a
t
_
v
e
c
t
(
)
j
f
o
r
t
0
;
<
5
;
i
+
+
)
i
n
Copyrighted material
sdv Contents
t
_
v
e
c
t
.
e
l
e
m
(
1
;
f
o
r
(
0
;
<
4
;
i
+
+
>
f
l
o
a
t
_
v
e
c
t
.
e
l
Copyrighted material
sdv Contents
e
m
(
f
l
o
a
t
(
1
.
5
)
;
c
o
u
t
"
I
n
t
e
g
e
r
V
e
c
t
o
r
:
i
n
t
_
v
e
c
t
.
s
h
Copyrighted material
sdv Contents
o
w
(
)
;
Copyrighted material
Similarly, the statement
basep = new Son{45, 20); // pointer to son
creates an object of type class Son dynamically and
assigns its address to the pointer basep. The statement
cout « basep->GetAge() « endl; //
calls Son::GetAge invokes the member function
GetAge () of the class Son (see Figure 3.5). If a call to
a non-virtual function is made in this case, it will
invoke the member function of the base class Father
instead of the derived class Son. Note that the s^me
pointer is able to invoke base or derived class's
member function depending on the class's object to
which it is bound (and this is true only with virtual
functions).
It is important to note that, virtual functions must be
accessed through the pointer to a base class. However^
they can be accessed through objects instead of
pointers, but note that the runtime polymorphism is
achieved only when a virtual function is accessed
through the pointer to a base class. Also another
important aspect is that, when a function is defined as
virtual in the base class and if the same function is
redefined in the derived class, that function is also
treated as virtual function by default. Only class
member functions can be declared as virtual
functions. Regular functions and friend functions do
not qualify as virtual functions.
) ;
When objects of template class are created using the
statement such as,
m
y
Copyrighted material
sdv Contents
c
l
a
s
s
<
f
l
o
a
t
,
1
0
>
n
e
w
l
;
t
h
e
c
o
m
p
i
l
e
r
c
r
e
a
t
e
s
t
h
e
f
o
l
l
o
w
i
n
g
Copyrighted material
sdv Contents
c
l
a
s
s
:
class myclass
{
float arr[10J;
);
Again if a statement such as,
myclass <int, 5> new2; is encountered for
creating the object new2, the compiler creates the
following class:
Run1
E
n
t
e
r
N
u
m
b
e
r
1
:
1
0
E
n
t
e
r
N
u
m
b
e
r
2
:
2
t
r
y
i
n
g
d
i
v
i
s
Copyrighted material
sdv Contents
i
o
n
o
p
e
r
a
t
i
o
n
.
.
.
s
u
c
c
e
e
d
e
d
n
u
m
l
/
n
u
m
2
5
Run2
E
n
t
e
r
N
u
m
b
e
r
1
:
1
0
E
n
t
e
r
N
u
Copyrighted material
sdv Contents
m
b
e
r
2
:
0
t
r
y
i
n
g
d
i
v
i
s
i
o
n
o
p
e
r
a
t
i
o
n
.
.
.
f
a
i
l
e
d
E
x
c
e
p
t
i
o
n
:
D
i
v
i
d
e
-
B
y
-
Z
e
Copyrighted material
sdv Contents
r
o
In
m
a
i
n
(
)
,
t
h
e
t
r
y
-
b
l
o
c
k
t
r
y
{
result = numl.div( num2 ) ;
)
invokes the member function div {) to perform the
division operation using the function defined in the
number class. (See Figure 3.6.)
Copyrighted material
sdv Contents
c
h
a
r
u
n
s
i
g
n
e
d
c
h
a
r
Size qualifiers (short and long) cannot be applied to
the char and float data types and sign qualifiers
(signed and unsigned) cannot be applied to float,
double, and long double.
D
a
i
a
l
y
p
e
:
c
h
Copyrighted material
sdv Contents
a
r
.
i
n
t
,
f
l
o
a
t
.
e
t
c
.
Variable name
"
H
e
l
l
o
W
o
r
l
d
"
;
i
n
t
Copyrighted material
sdv Contents
1
0
;
for(
i
n
t
0
;
<
1
0
;
i
+
+
c
o
u
t
<
<
i
;
Note that the variables d and i are defined at the
point of their usage.
Copyrighted material
sdv Contents
float c , f ;
cout < < "Enter temperature in Celsius: " ;
cin >> c ;
f = 1.8 * c + 32;
cout <<
"Equivale
nt
fahrenheit
=■«£«
endl; cout
<< "Enter
temperatu
re in
fahrenheit
: "; cin
» f;
c = (f - 32) / 1.8;
cout < < "Equivalent Celsius = " « c ;
}
Run
E
n
t
e
r
t
e
m
p
e
r
a
t
u
r
e
i
n
C
e
l
s
i
u
s
:
E
q
u
i
v
a
l
e
n
t
f
a
h
r
Copyrighted material
sdv Contents
e
n
h
e
i
t
4
1
Enter temperature in fahrenheit: ,
Equivalent Celsius = 4.444445
4.10 Qualifiers
Qualifiers modify the behavior of the variable type, to
which they are applied. Qualifiers can be classified
into two types:
« Size qualifiers
«
S
i
g
n
q
u
a
l
i
f
i
e
r
s
C
o
n
s
i
d
e
r
t
h
e
v
a
r
i
a
b
Copyrighted material
sdv Contents
l
e
d
e
f
i
n
i
t
i
o
n
s
t
a
t
e
m
e
n
t
:
i
n
t
i
;
It specifies that i is an integer, which takes both
positive and negative values. That is, i is a signed
integer by default. The above definition could also be
written as:
signed int i ;
Prefixing of the qualifier s igned explicitly, is
unnecessary, since int data type definitions arc s
igned by default. If the variable i is used to hold only
positive values (for example, if it is used to hold the
number of students in a class), it can be defined as
follows: unsigned int i ;
Here, the qualifier unsigned is applied to the data type
int. This qualifier modifies the behavior of the integer
so that a variable of this type always contains a
positive value.
Copyrighted material
sdv Contents
Copyrighted material
110 Mastering C++
In most compilers available on DOS, the size of a short int and an int are the same (16 bits). A long int occupies
32 bits. But in 32-bit compilers such as GNU C/C++, an int and a long int are of the same size (32 bits), while a
short int is 16 bits. On the other hand, almost all UNIX compilers have the size of int as 16 bits, int and long int
being 32 bits.
sizeof operator
The operator sizeof returns the number of bytes required to represent a data type or variable. It has the following forms:
sizeofi data-type )
sizeof{ variable )
The data type can be standard or user defined data type. The following statements illustrate the usage of sizeof operator:
int i, j ; float c;
sizeof ( int ) returns 2 or 4 depending on compiler implementation
sizeof ( float ) returns 4
sizeof ( long ) returns 4
s i zeo f ( i ) returns 2 or 4 depending on compiler implementation
sizeof { c ) returns 4
The program size.cpp determines the size of an integer and its variants. It uses the function sizeof {), which gives the
size of any data type in bytes.
Run1
sizeof( char ) = 1 sizeof( short } = 2
sizeof( short int ) = 2 sizeof( int ) = 2
sizeof( long ) = 4 sizeof( long int ) = 4 ?
izeof( float ) = 4 sizeof( double ) = 8
sizeof( long double ) = 10
Copyrighted material
Chapter 4: Data Types, Operators and Expressions 111
Run2
sizeoft char ) = i sizeof( shore ) = 2
sizeofi shore int ) = 2 sizeof{ int ) = 4
sizeof( long ) = 4 sizeof( long int ) = 4
sizeof( float ) = 4 sizeof( double ) = 8
sizeoft long double ) = 10
Note: The output displayed in Runl is generated by executing the program on the DOS system compiled with
Borland C++ compiler. Run2 fs generated by executing the program on the UNIX system.
The name of the variable type is passed to the sizeof operator in parentheses. The number of bytes occupied
by a variable of that type is given by the sizeof operator. The sizeof operator is very useful in developing
portable programs. It is a bad practice to assume the size of a particular type, since its size can vary from
compiler to compiler.
The sizeof operator also takes variable names and returns the size of the variable given, in bytes. For
example, the statements
int i ;
cout << "The size of i is " << sizeof (i); will output
The size of i is 2
The result of sizeof (int) or sizeof {i) will be the same, since i is an int. However, it is a better practice to pass a
variable name to the sizeof operator; if the data-type of i has to be changed later, then rest of the program need
not be modified.
Sign Qualifiers
The keywords signed and unsigned are the two sign qualifiers which inform the compiler whether a variable
can hold both negative and positive numbers, or only positive numbers. These qualifiers can be applied to the
data types int and char only. For example, an unsigned integer can be declared as
unsigned int i;
As mentioned earlier, signed int is the same as int (i.e., int is signed by default). The char data type can be
T- True, F- False
Copyrighted material
Chapter 4: Data Types, Operators and Expressions 111
The unary negation operator (!) has a higher precedence amongst these, followed by the logical AND (&&)
operator and then the logical OR (| |) operator, and are evaluated from left to right.
The logical operator is used to connect various conditions to determine whether a given year is a leap year
or not. A year is a leap year if it is divisible by 4 but not by 100, or that is divisible by 400. The program leap.
epp illustrates the use of the modulus operator.
/ / leap.cpp: detects whether year is leap or not #include <iostream.h>
void main() I
int year;
cout << "Enter any year: "; cin » year;
if( (year % 4 == 0 && year % 100 != 0 ) || (year % 400 == 0) )
cout << year << " is a leap year"; else
cout « year « " is not a leap year";
}
Run1
Enter any year: 1996
1996 is a leap year
Run2
Enter any year: 1997
1997 is not a leap year
In main (), the statement
if( (year % 4 == 0 fcfc year % 100 != 0 ) || (year % 400 == 0) ) can be replaced by
if ( (I (year % 4) && year % 100 ! = 0 ) ] | .' (year % 400) )
Operator Meaning
& Bitwise AND
1 Bitwise OR
Bitwise EX-OR
- Bitwise complement
« Shift left
>> Shift right
Table 4.9: Bit-wise operators (i) Logical
Bit-wise Operators
Logical bit-wise operators perform logical operations such as AND, OR, EX-OR, NOT between corre sponding
bits of operands (if binary) and negation of bits (if unary).
Unary Operator: One's Complement Operator (~)
The complement operator causes the bits of its operand to be inverted, i.e., 1 becomes 0 and 0 becomes I. For
instance, the largest possible number, which can be stored in an unsigned integer can be found as follows.
When one's complement operator is applied on this word holding zero, all the bits will be inverted to ones and
a new value becomes the largest possible number. The program large. cpp illustrates this conversion process.
/ ■ large.cpp: detects largest possible unsigned integer •include
<iostream.h> int mainf) {
unsigned u = 0;
cout « "Value before conversion: ■ << u << endl; u - ~u;
cout << "Value after conversion : " << u << endl; return 0;
)
Run1
Value before conversion: 0 Value after
conversion : 65535
Run2
Value before conversion: 0
Value after conversion : 4294967295
Copyrighted material
Chapter 4: Data Types, Operators and Expressions 111
Bitwise OR operator: a I b
a 0000 0000 0000 1101
Left-Shift «
drop off «—| 0000 0000 0000 1101 \*— insert 0's after Left-bit shift by 3 places I.e., a « 3
I 0000 0000 0110 1000 I
The three leftmost bits drop off due to the left shift (i.e., they are not present in the result). Three zeros are
inserted in the right. The effect of shifting a variable to the left by one bit position is equivalent to multiplying
the value by 2. If the initial value of a is 13, shifting left by 3 bit positions yields 13*8=104.
Copyrighted material
Chapter 4: Data Types, Operators and Expressions 111
While multiplying a number with a power of 2, considerable savings in execution time can be achieved by
using the left bit-shift operator instead of the multiplication operator, since a shift is faster than multiplication.
Right Shift Operator
Consider the statement c = a >> 2,-The value of a is shifted right by 2 positions. Since the value of a is 0000
0000 0000 1101 the value of c after the execution of the above statement is 0000 0000 0000 0011 (3 in
decimal) and is illustrated below:
Right-Shift »
insert 0's 0000 0000 0000 11Q3~]—»drop off
after right shift by 2 places i.e., a » 2 |
0000 0000 0000 0011 I
The 2 rightmost bits drop off (are not present in the result), and zeros are inserted in the left. The effect of
shifting a variable to the right by one bit position is equivalent to dividing the value by 2 (i.e., divide by 2 and
truncate the result). As the initial value of a is 13, shifting it right by 2 bit positions yields the value 3 (the
result of dividing 13 by 4 and truncating the result). Note that if the negative number is shifted right, then 1 is
inserted at the left for every bit shifted to the right.
The program extract.cpp illustrates the binary operators. It reads an integer and prints the value of a
specified bit in the integer. The position of bits are numbered starting with 0 from right to left. For example, to
find the value of the second bit of an integer i, it is necessary to shift i to the right by two bits, and take the least
significant digit.
// extract.cpp: Fishing the nth bit ♦include
<iostream.h> void main ( )
{
/ / a is the input integer and n, the bit position to extract
int a, n, bit;
cout « "Enter an integer:
cin >> a;
cout « "Enter bit position to extract: ";
cin >> n;
bit = ta » n) & 1; / / bit is the value of the bit extracted (0 or 1) cout « "The bit is " << bit;
)
Run
Enter an integer: 10.
Enter bit position to extract: Z
The bit is 1
In main (), the statement
bit = (a » n) & 1;
first shifts a to the right by n bits and then masks (clears) all the bits of a except the least significant bit
(rightmost bit), retaining the bit which is required. Parentheses are not required in the above statement, since
the operator » has more precedence than & (i.e., in an expression, if both » and & are present, the » operator is
executed first). Since this fact is not obvious, it is always better to use parentheses in such situations, for the
sake of readability.
Copyrighted material
Chapter 4: Data Types, Operators and Expressions 12"
The program max. cpp reads two integers and displays the value of the larger of the two numbers computed using
the ternary operator. If they are equal, then naturally, either of them can be printed.
// max.cpp: finding the maximum using the conditional operator ♦include <iostream.h> void main () {
int a, b, larger;
cout « "Enter two integers: ";
cin » a >> b;
larger = a > b ? a : b;
cout « "The larger of the two is " « larger;
}
Run
Enter two integers: XQ. 20. The larger of
the two is 20
/ / Oddeven.Cpp: checks whether the number is odd or even ♦include <iostream.h> void main () {
int num; char
*str;
cout « "Enter the number: "; cin » num;
cout « "The number * << num « 1 is
cout « ((num % 2) ? "Odd" : " E v e n " ) ;
cout << endl « "Enter the number: "; cin >> num;
cout << "The number " « num « " is "; (num % 2) ? cout « "Odd"
: cout « "Even";
)
Run
Enter the number: iO. The
number 10 is Even Enter the
number: 25. The number 25 is
Odd
Copyrighted material
Chapter 4: Data Types, Operators and Expressions 133
The character 1 or L can be used to specify long double values. For example, 0 . 257L is a long double
constant.
Operator Meaning
\a Beep
\b Backspace
\f Formfeed
\n Newline
\t Horizontal tab
\\ Backslash
\' Single quote
\■ Double quote
\v Vertical tab
\? Question mark
\0 Null
\0ooo Code specified in octal
\xhh Code specified in hexadecimal
Copyrighted material
Contents xix
Copyrighted material
18.12............................................................................................. In-
Memory Buffers and Data Formatting....................................................................................... 695
18.13............................................................................................. Error
Handling During File Manipulations.......................................................................................... 696
call during execution, since the function body is substituted at the point of macro call during compila -
tion. Thereby the runtime overhead for function linking or context-switch time is reduced. The
directive #def ine, indicates the start of a macro function as shown in Figure 4.10. The macro function
specification spans for a maximum of one line only. However, macro function body can spread to
multiple lines if each new line is followed by A' character.
■---► Start of pre-processor directive indicator
■---► pre-compiler (pre-processor) directive
I- - -► name of the macro function
r
I—► macro parameters
C++ statements performing
Macro Function Operation
Examples:
#define inc( a ) a+1
♦define add{ a, b )
(a+b)
The program maxmacro.cpp illustrates the use of macro function in the computation of the
maximum of two numbers.
/ / maxmacro.cpp: maximum of two numbers using macros
♦include <iostream.h>
♦define max( a, b ) ( a > b ? . a : b )
void main()
{
cout << "max( 2, 3 ) = " << max( 2, 3 ) << endl;
cout « "max{ 10.2, 4.5 ) = ■ « max{ 10.2, 4.5 ) « endl;
int i = 5, j = 10;
cout << "i = ' « i « endl;
cout << "j = " « j « endl;
cout « "On execution of k ■ max( ++i, ++j );...' « endl; int k = max{ + + i, ++j ); cout << "i = ■ « i
<< endl; cout << "j = " << j << endl; cout << "k = " « k « endl;
)
Run
max( 2, 3 ) = 3
max( 10.2, 4.5 ) = 10.2
i=5
j - 10
On execution of k = max( ++i, ++j ); . . . i = 6 j
= 12 k = 12
In main (), the expressions
max( 2, 3 ) max( 10.2,
4.5 )
invoke the macro function max (). Unlike normal functions, macro functions can take parameters of
any data type. If arguments are in the form of expressions, they are not evaluated at the point of call,
but at the time of their usage. Thus, the statement
int k = max( ++i, ++j ); is processed
by the preprocessor as follows:
int k = { ++i > ++j ? ++i : ++j );
It can be observed that, the variable with greater value, will be incremented twice. The macro function
body can spread across multiple lines as follows:
#define print( n ) \
for{ int i = 0; i < n; i++ ) \ cout « i;
Copyrighted material
operator. In order to override the precedence, braces can be used. For example, the statement d = la +
b) * c;
would add a to b first, multiply the result by c and assign the product to d. Associativity of an operator
can be from left-to-right or right-to-left. For example, in the expression d = a - b - c;
the leftmost minus is evaluated first and then the second minus is evaluated, causing c to be subtracted
from the result. Thus, in case where several operators of the same type appear in an expression without
braces, the operators are normally evaluated starting from the leftmost operator, proceeding rightward,
hence the minus operator associates from left to right. On the other hand, the assignment operator
associates from right to left. For example, in the statement d = a = c;
the second (right-most) assignment operator is evaluated first. The variable c is assigned to a and then
this value is assigned to d.
Like most programming languages, C++ does not specify the order in which the operands of an
operator are evaluated. Such operators are &&, | |, ?:, and ','.) For example, in the statement such as x =
g() + h i ) ;
tj () may be evaluated before h () or vice versa; thus if g () or h () alters a variable (global) on which
the other depends, then the resultant value of x is dependent on the order of evaluation. Similarly, the
order in which function arguments are evaluated is not specified, so the statement
Copyrighted material
Operator precedence and associativity
Copyrighted material
Copyrighted material
142 Mastering C++
add( ++n, pow( 2 , n ) ); can produce different results with different compilers. However,
most C+ + compilers evaluate function arguments from right to left. There are cases such as in function
calls, nested assignments, increment and decrement operators cause side effects—some variable is
changed as a by-product of the evaluation of the expression. The (C language and hence, C++)
standard intentionally leaves such matters unspecified. When side effects (variable modification)
take place within an expression, it is left to the discretion of the compiler, since the best order
depends strongly on the machine architecture.
The moral is that developing a code that depends on the order of evaluation, is not a good
programming practice in any language. Hence, it is necessary to know what to avoid, but if it is not
known how they are treated, the programmer should not be tempted to take advantage of a particular
implementation.
Review Questions
4.1 What are variables ? List C++ rules for variable naming.
4.2 Why output and Output are considered as different identifiers ?
4.1 What arc keywords ? List keywords specific to C++. Can these keywords be used as
variables ?
4.2 What is a data type ? What are the different data types supported by C++ ?
4.6 Wl.at is new about C++ in terms of the variable definition ?
4.7 What is the difference between a character and a character string representation ?
4.8 What is an-expression ? Is this different from a statement ? Give reasons.
4.9 List categories of operators supported by C++.
4.10 What are qualifiers ? Illustrate them with examples.
4.11 Develop an interactive program to compute simple and compound interest.
4.12 List evaluation steps for the expression (a+(b*c))*c+d/2.
4.13 Write an interactive program to find the largest of two numbers.
4.14 How C++ represents true and false values ? Are the expressions !a and a==0 have the
same meaning ? Give reasons.
4.15 Write a program to determine the type of compiler (whether 16 or 32-bit) used to compile
it.
4.16 Write a program to multiply and divide a given number by 2 without using * and / operators.
■1.17 Illustrate how compound assignment operators allow to write compact expressions ?.
. 18 What is the effect of the following expressions if i=l and j =4 ?
a) i + + b) j = c) j = ++j; d) i+++j e) i = i++++*j;
4.19 Write an interactive program to find elder among you and me using the ternary operator.
4.20 What is the outcome of the statement: a= (a=10 , a+ + , a—) ; if a holds the value 5
initially.
4.21 What is type conversion ? What are the differences between silent and explicit type
conversion? Write type conversion steps required for evaluating the statement:
z=i+b+ j-k/4; (where i and j are ints, b is float, and k is double, and z is long type). 4.2-
What are escape sequences ? Write a program to output messages in double quotes.
4.23 What ar- macros ? Write a program to find the minimum of two numbers using macros.
What is the output of the statement: a = min( ++a, ++b); (if a = 2 and b = 4).
4.24 What is operator precedence ? Arrange the following operators in the order of their
precedence:
*. +. (). !. ++, --. |. | |. &. /,and &&
4.25 What is the significance of the associativity of operators ? What is the order of evaluation of
the
operator ? : in the statement
a = i > j ? i : j;
Copyrighted material
Chapters: Control Flow 42
Runl
Enter your age: 15
you are a teen-aged person, good!
Run2
Enter your aae:-20
In main (), the statement
if( age > 12 && age < 20 ) first evaluates the test expression and executes the if-part only when it is
true. In Runl, the input data entered is 15 which lies between 13 and 19 and hence, the statement
cout << "you are a teen-aged person, good!'; gets executed. Whereas, in Run2. the input data is 20
which does not lie within this range and hence, the control proceeds to the next statement.
Run
Enter three floating-point numbers: 10 .2 15 . 6 12_Ji Largest of the three
numbers =15.6
Copyrighted material
Chapters: Control Flow 43
else » /
>
If-else condition
entry
▼ .....................✓ . , r- . ■ •......."..............
for (^initialization .''condition';;-; updacion ) V
true i false
}
statement; «-
Bun
How many integers to be displayed: £
0
1
2
3
4
In main (), the statement
fort int i = 0; i < n; i++ ) cout « i « endl;
has four components. The first three components enclosed in round braces and separated by semicolons are the
following:
int i = 0 i < n i++
The first component int i = 0 is called the initialization expression and is executed only once prior to the statements
within the for loop. The second component i < n is called the test expression and
Copyrighted material
Chapters: Control Flow 44
is evaluated every time before execution of the loop body. If this expression is true, the statement in the loop gets
executed. In case it is false, the loop terminates and the control of execution is transferred to the statement following the
for loop. The third component is called update expression, and is executed after every execution of the statement in the
loop. The fourth component is the loop-body. The program sumsql. cpp, finds the sum and the sum of squares of the first
15 positive even integers.
// sumsql .Cpp: sum of first 15 even numbers and their squares' sum #include<iostream.h> void main {) {
int i;
int sum = 0, sum_of_squares = 0; for( i =2; i <=
30; i += 2 ) {
sum += i;
sum_of_squares += i*i;
}
cout « "Sum of first 15 positive even numbers = " << sum << endl; cout « "Sum of their squares = " «
sum_of_squares;
)
Run
Sum of first 15 positive even numbers = 240 Sum of their
squares = 4960
Run
Sum of first 15 positive even numbers = 240 £;um of their squaj
es = 4960
Run
Enter the number of lines: 5, X
2 3 23 4 5 4 34
5 6 7 6 5 4
5 6 7 8 9 8 7 6
entry
------1 false
▼ .........- < - " ~ \
-while ('.expression:) \
/{ .................................i' <
i ' true ,'
)
statement Figure 5.5: Control flow In while loop
/ / COUnt2.Cpp: display numbers 1. .N using while loop
linclude <iostream.h> void main { ) {
int n;
cout « "How many integers to be displayed:
cin » nj int i = 0;
while{ i < n ) <
cout « i « endl; i++;
)
)
Run
How many integers to be displayed: 5_
0
1
2
3
4
The while loop is often used when the number of times the loop has to be executed is unknown in
advance. It is illustrated in the program averagel. cpp.
// averagel.cpp: find the average of the marks •
include <iostream.h> void main ( ) {
int i , sum = 0, count ■ 0, marks;
cout « "Enter the marks, -1 at the e n d . . . \ n " ;
cin » marks;
while( marks ! = -1 )
{
sum + = marks;
count++;
cin > > marks;
}
float average = sum / count;-
cout « "The average is ■ « average;
)
Run
Enter the marks, -1 at the end...
afl
2
1
£
2
1
A
z
l
Copyrighted material
Chapters: Control Flow 46
The average i s 77
The first cin statement, just before the while loop, reads the marks scored in the first subject and
stores in the variable marks, so that the statement inside the loop can have some valid data to operate.
The cin statement inside the loop reads the marks scored in the other subjects one by one. When -1 is
entered, the condition
marks ! = -1
evaluates to false in the while loop. So, the while loop terminates and the program execution proceeds
with the statement immediately after the while loop, which in the above program is
average = sum / count; Consider the case when the user inputs -1 as the first marks. The
condition in the while statement evaluates to false, and the statements inside the loop are not executed
at all. In this case, the value of count continues to be zero, so, while computing the average it leads to
division by zero causing a run-time error. This can be prevented by using the if statement as follows;
if( count != 0 )
average = sum / count;
The above statement can also be written as
iff count )
average = sum / count;
Any expression whose value is nonzero is treated as true. The program binary. cpp illustrates such
situations. It uses the while construct to convert a binary number to its decimal equivalent. The shift-
left operator«is used for shifting bits stored in a variable in this program.
do {
cout < < i « endl; i +
+;
} while( i < n ) ;
)
Run
How many integers to be displayed: 5.
0
1
2
3
4
To realize the usefulness of the do. .while construct, consider the following problem: The user
has to be prompted to press m or f. In reality, the user can press any key other than m or f. In
such a case, the message has to be shown again, and the users should be allowed to re-enter one
of the two options. An ideal construct to handle such a situation is the do. .while loop as
illustrated in the program dowhi le. cpp.
/ / dowhlle.cpp: do. .while loop for asking data until i t i s valid ♦include <iostream.h> void main
()
{
char inchar;
do
{
cout « "Enter your sex ( m / f ) : ■;
cin » inchar; ) while{ inchar ! = ' m ' && inchar ! =
' f ' ) ; i f ( inchar == 'm' )
cout « 'So you are male, good!"; else
cout « "So you are female, g o o d ! ' ;
J
Run
Enter your sex ( m / f ) : 3
Enter your sex ( m / f ) :
Enter your sex ( m / f ) : m So
you are male, good!
In main ( ) , the do. . while loop keeps prompting for the user input until the characterm for
male or f for female is entered. Such validation of data is very important while handling sensitive
and critical data.
The solution to certain problems inherently requires data validation only after some
operation is performed as illustrated in the program pal. cpp. It checks if the user entered
number is a palindrome using the do-while construct.
The program averagel - cpp discussed earlier has the following code: cin >> marks; while{ marks !
= -1 )
<
sum + = marks;
count**;
47 Mastering C++
Copyrighted material
Chapter 5: Control Flow 48
Run
Enter a number (0 to quit) :
Enter a number (0 to quit) : 2£
Enter a number (0 to quit): ^£
skipping this number.
Enter a number (0 to quit) : XSL
Enter a number (0 to quit) : SI
end of data entry.
Total of all +ve numbers is 40
In do. . while loop of the above program, on encountering break, control is transferred outside the loop. On
encountering continue, control is transferred to the while condition which is always true (nonzero). Figure 5.10 shows
action differences between break and continue statements in loops. The break and continue statements must be
judiciously used and their indiscriminate use can hamper the clarity of the logic.
for i: { for (
i f ( expression ) i f ( expression } break;%
continue;-------------- \
}
) statement;*"
statement;
Copyrighted material
2 Mastering C++
cost of software development and maintenance and declining hardware cost over several years is
depicted in Figure 1.1. Software maintenance is the process of modifying or extending the capabilities
of the existing software It requires mastery over the understanding and modifying the existing
software, and finally revalidating the modified software.
100
found:
// Element found
Except in cases such as the one cited above, the use of the goto statement must be avoided.
It is possible to use goto statement to jump from outside a loop to inside the loop body, but it is
logically incorrect. Hence, goto jumps shown in Figure 5.11 would cause problems and therefore must
be avoided.
Copyrighted material
2 Mastering C++
Run1
Enter your age: 14
you are a teen-aged person, good!
Run2
Enter your age: 50
you are a teen-aged person, good!
In main (), the statement
if( age > 12 && age < 20 ); effectively does nothing; observe the semicolon after the
condition statement. The program displays the same message for any type of input data. Whether the
input age lies in range of teenage or not, it produces the message
you are a teen-aged person, good! See Run2 output which
shows even 50 year aged person as teen-aged!
Equality Test
The program agecmp. cpp is written for comparing ages of two persons. It prints the illogical message
except for some typical value.
Run1
Hi! my age is 25 What
is your age ? 21
We are born on the same day. Are we twins!
Run2
Hi! my age is 25 What
is your age ? XSL
We are born on the same day. Are we twins!
Run3
Hi! my age is 21
What is your age ?
Copyrighted material
2 Mastering C++
i f( myage = yourage ) has the expression myage = yourage. It assigns the contents of the
variable yourage, to myage. It is evaluated to true, for all nonzero values of yourage and hence, the
program prints the same message except for zero input value. The programmer must be careful while
writing the statement, which checks for the equality of data.
Copyrighted material
Chapter 6: Arrays and Strings 169
Run
Enter person 1 age: 21
Enter person 2 age: 40. Enter
person 3 age: 2£ Enter person 4
age: 27 Enter person 5 age: 25
Average age =29
The above program uses distinct statements to read and add the age of each person. The resulting value of
summation is stored in the variable sum Finally, the average age is computed by dividing the sum by 5. A program
written in this style is very clumsy, and difficult to enhance. If there are a large number of individuals, the number of
statements increase proportionately. A more elegant approach is to use an array type variable to store the age of
persons, and process them using loops as illustrated in the program age2 . cpp.
/ / age2.cpp: arrays to handle data which are of the same type ♦include <iostream.h> void main () {
int age[5]; // array definition
float sum = 0;
fort int i = 0; i < 5; i++ )
{
cout << "Enter person " « i+1 « " age: "; cin » age(i);
// reading array elements
)
fort i = 0; i < 5; i++ )
sum += age[il; // array manipulation cout « "Average age =
" « sum/5;
Run
Enter person 1 age: 23
Copyrighte
d material
6.3 Array Illustrations
The program elder. cpp finds the age of the eldest and youngest person in a family. It reads the ages of all the members
of a family stores them in an array and then scans the array to find out the required information.
cout « "Enter person" « i+1 « " age: "; cin >> age[i];
)
// finding youngest and eldest person age begins here
younger = age[0];
elder = age[0];
for (i = I; i < n; i++)
(
if( age[i] < younger )
younger = age[i]; else
if{ age[i] > elder ) elder =
age[i];
>
// finding younger and elder person ends here
cout « "Age of eldest person is " « elder « endl;
cout << 'Age of youngest person is ■ << younger;
)
Run
How many persons are there-in list <max-25> ? 7
Enter personl age: 25.
Enter person2 age: 4
Enter person3 age: £5_
Enter person4 age: lfi.
Enter person5 age: i5_
Enter person6 age: 22.
Enter person7 age: 22.
Age of eldest person is 45
Age of youngest person is 4
Bubble Sort
A classical bubble sort is the first standard sorting algorithm most programmers learn to code. It has gained popularity
because it is intuitive, easy to write and debug, and consumes little memory. In each
Copyrighte
d material
case 9: case 10:
gap = 11;
break;
)
flag = 1;
int top = size - gap;
for( i = 0; i < top; i++)
{
j = i+gap;
if( age[ij > age[j] ) {
flag = 0; // still not sorted and requires next iteration // exchange contents of age[i] and
agelj] temp = age[iJ; agelij = age[jJ; age[j] = temp;
>
}
} while( Iflag || gap > 1 ); // sorting ends here cout
<< 'Sorted list..." « endl; for( i = 0; i < n; i ++ ) cout «
age[i] « " ■;
}
Run
How many elements to sort <max-25> ? 2
Enter age[ 0 ]: 2
Chapter 6: Arrays and Strings 169
Enter age[ 1 ] : 5
Enter age[ 2 ] : 2
Enter age[ 3 ] : 4
Enter age[ 4 ] : £
Enter age[ 5 ] : 1
Enter age[ 6 ] : £
Sorted list...
1234569
Although the algorithm for comb son and shell sort appear to be very similar (both use a gap and a shrink factor),
they do in fact perform differently. The shell sort does a complete sort (until there are no more swaps to be made) for
each gap size, comb sort makes only a single pass for each gap size-it can be thought of as a more optimistic version of
the shell sort. There are other differences that result from this optimism: The ideal shrink factor for shell sort is 1.7.
compared with 1.3 of comb sort. The complexity obtained by plotting sorting time against the list of size n, for shell
sort, appears as a step function of (n*log 2n*log2n), whereas for comb sort it approximates to a flatter curve of (n *
logjn).
Run
Enter your name: Smrithi strlen( si ) :
7
String Copy
The string function strcpy() copies the contents of one string to another. It takes two arguments, the first argument is the
destination string array and the second argument is the source string array. The source string is copied into the
destination string. The program strcpy.cpp illustrates the use of strcpy () to copy a string.
Run
Enter a string: Garbage. strcpy( s2,
si ): Garbage
String Concatenation
The siring function strcat () concatenates two strings resulting in a single string. It takes two arguments, which
are the destination and source strings. The destination and source strings are concatenated and the resultant string
is stored in the destination (first) string. The program strcat. cpp illustrates the use of strcat {) to concatenate two
strings.
// Strcat.cpp: string concatenation •include
<iostream.h> •include <string.h> void main()
Run
Enter string si: £ Enter string
s2: ++ strcat( si, s2 ) : C+ +
String Comparison
The string function strcmp () compares two strings, character by character. It accepts two strings as parameters
and returns an integer, whose value is
♦<0 if the first string is less than the second
♦ == 0 if both are identical
♦>0 if the first string is greater than the second
Whenever two corresponding characters in the string differ, the string which has the character with the
higher ASCII value is greater. For example, consider the strings hello and Hello! !. The first character itself
differs. The ASCII code forh is 104. while the ASCII code forH is 72. Since the ASCII code of h is greater, the
string hello is greater than the string Hello!. Once a differing character is found, there is no need to compare
remaining characters in the string. The program strcmp.cpp illustrates the use of strcmp () to compare two
strings.
Copyrighted material
186 Mastering C++
Run
Enter string si: Computer Enter string s2:
Computing
strcmp( si, s2 ) : Computer is less than Computing
Run
Enter a string: Smrithi
strupr( temp ): SMRITHI
strlwr( temp ) : smrithi
Copyrighted
material
6.7 Arrays of Strings
An array of strings is a two dimensional array of characters and is defined as follows:
char array-name\row_size][column_size}; For instance, the statement
char person[10][15] ; defines an array of string which can store names of 10 persons and each name cannot exceed 14
characters; 1 character is used to represent the end of a string. The name of the first person is accessed by the expression person[0],
and the second person by person[l], and so on. The individual characters of a string can also be accessed. For instance, the first
186 Mastering C++
character of the first person is accessed by the expression person[0] [0] and the fifth character in the 3* person's name is accessed
by person [21 [4 ]. The program names . cpp illustrates the manipulation of an array of strings.
// names.cpp: array of strings storing names of the persons
♦include <iostream.h>
♦include <string.h>
const int LEN = 15;
void main ()
{
int i, n;
char person[10][LENJ;
cout << "How many persons ? ";
cin >> n;
fort i = 0; i < n; i + + )
{
cout << "Enter person" « i + 1 << " name: "; cin » person[i];
}
cout<< "-------- cout<< ----------------------------------------------\n-
cout « " P * Length In lower case In UPPER case\n"
Person Name ..............-----------------------------------\n"
for ! i - i < n; i++ J {
cout.width( 2 ) ;
cout « i + 1;
cout.width( LEN ) ;
cout << person[i] << " *;
cout .width ( 2 ) ,-
cout << strlen{ person[il ) « " cout.width{ LEN > ; cout <<
strlwr(person[i]); cout.width< LEN ) ;
cout << strupr(person[i]) << endl;
}
cout« "-----------------------------------------------------------------------------------------------------\n";
.90
Mastering C++
a::.:
a[1001 = 200; cout «
a[101J ;
= 5; cout
« aC-1 J ;
Does the compiler reports an error when illegal accesses are made to an array ?
6.4 What are multi-dimensional arrays ? Explain their syntax and mechanism for accessing their ele-
ments.
6.5 Write an interactive program for calculating grades of N students from 3 tests and present the
result in the following format:
variance = ~ J) (xi -
m) s = V variance
6.12 Write a program to find the transpose of a matrix. (The transpose can be obtained by inter-
changing the elements of rows and columns).
6.13 Write a program to find the saddle points in a matrix. It is computed as follows: Find out the
smallest element in a row. The saddle point exists in a row if an element is the largest element in
that corresponding column. For instance, consider the following matrix:
7 5 6 10 2 3 1 3 3 The saddle point results are as listed below: In row 1,
saddle point exists at column 2. In row 2, saddle point does not exist. In row 3, saddle point does not
exist. 6 14 Write an interactive program to multiply two matrices and print the result in a matrix form.
i
I
Copyrighted material
6 Mastering C++
Monolithic Programming
The programs written in these languages exhibit relatively flat physical structure as shown in
Figure 1.3. They consist of only global data and sequential code. Program flow control is
achieved through the use of jumps and the program code is duplicated each time it is to be used,
since there is no support of the subroutine concept and hence, it is suitable for developing small
and simple applications. Practically, there is no support for data abstraction and it is difficult to
maintain or enhance the program code.
Examples: Assembly language and BASIC
2 ..........
goto 10&
goto 55
goto 3
goto T5
goto 6
100 ..............
Procedural Programming
Programs were considered as important intermediate points between the problem and the
computer in the mid-1960s. Initially, software abstraction achieved through procedural
abstraction grew directly out of this pragmatic view of software. Subprograms were originally
seen as labor-saving devices but very quickly appreciated as a way to abstract program functions
as shown in Figure 1.4.
The following are the important features of procedural programming:
♦ Programs are organized in the form of subroutines and all data items are global
♦ Program controls are through jumps (gotos) and calls to subroutines
♦ Subroutines are abstracted to avoid repetitions
♦ Suitable for medium sized software applications
♦ Difficult to maintain and enhance the program code
Examples: FORTRAN and COBOL
Global Data
Subprograms
y
;
Copyrighted material
6 Mastering C++
t
;
cout<<"Value of x and y in swap after exchange: "<< x <<" " << y << endl;
)
v
o
i
'
d
m
a
i
n
{
)
{
int a, b;
cout << "Enter two integers
<a, b>: " ; cin » a >> b; swap £
a, b ) ;
cout « "Value of a and b on swapt a, b I in mainO : ■ << a << " " « b;
)
Run
Enter two integers <a, b>: 10 20 Value of x
and y in swap before exchange: 10 20 Value
of x and y in swap after exchange: 20 10
Value of a and b on swapt a, b ) in mainO : 10
20
In main
(),
the
state
ment
swa
p( x,
y)
invokes the function swap ( ) and assigns the contents of the actual parameters a and b to the
formal parameters x and y respectively. In the swap ( ) function, the input parameters arc
exchanged, however it is not reflected in the caller; actual parameters a and b do not get modified
(see Figure 7.8).
Copyrighted material
6 Mastering C++
Co
pyrig
hted
mate
rial
Pass by Address
C++ provides another means of passing values to a function known as pass-by-address. Instead of
passing the value, the address of the variable is passed. In the function, the address of the
argument is copied into a memory location instead of the value. Thfe de-referencing operator is
used to access the variable in the called function.
Run
Enter two integers <a, b>: 10 20
Value of a and b on swap ( a, b ) : 20 10
In main (), the
statement
swapt &x,
&y )
invokes the function swap and assigns the address of the actual parameters a and b to the formal
parameters x and y respectively.
int , b; int t;
a
Copyrighted material
6 Mastering C++
t=*x;
swap(&a, &b); 20,
/ >
)
/?
1552
<----10------
s ■-1552-- X
y
/1554 1 ----20------ r-1554-
Pass by Reference
Passing parameters by reference has the functionality of pass-by-pointer and the syntax of call-
by-value. Any modifications made through the formal pointer parameter is also reflected in the
actual parameter. Therefore, the function body and the call to it is identical to that of call-by-
value, but has the effect of call-by-pointer.
To pass an argument by reference, the function call is similar to that of call by value. In the
function declarator, those parameters, which are to be received by reference must be preceded by
the & operator. The reference type formal parameters are accessed in the same way as normal
value parameters. However, any modification to them will also be reflected in the actual
parameters. The program swap3. cpp illustrates the mechanism of passing parameters by
reference.
// swap3.cpp: swap integer values by reference
•include <iostreara.h>
void swap{ int & x, int & y }
{
int t; // temporary used in swapping t = x;
x = y; y = t;
)
void
main() (
int a, b;
cout << "Enter two integers <a, b>: "; cin » a
» b; swap( a, b );
cout « "Value of a and b on swapt a, b ) : ■ << a « " " « b;
)
Run
Enter two integers <a, b>: 1Q_
Value of a and b on swapt a, b ) : 20 10
In main (), the statement
swap t a,
b ) ; is translated into
swap ( & a, & b ) ; internally during
compilation. The function declarator
void swapt int & a, int & b ) indicates that the formal parameters are of reference type
and hence, they must be bound to the memory
Copyrighted material
6 Mastering C++
location of the actual parameter. Thus, any access made to the reference formal parameters in the
swap () function refers to the actual parameters. The following statements in the body of the swap
() function:
t
=
x;
x
=
y;
y
=
t;
(as treated by the compiler) have the following interpretation
internally: t = *x; // store the value pointed by x into t
*x = *y; // store the value pointed by y into location pointed by x *y = t ; // store the
value hold by ' t ' into location pointed by y
This is because, the formal parameters are of reference type and therefore the compiler treats
them similar to pointers but does not allow the modification of the pointer value (cannot be made
to point to some other variable). Changes made to the formal parameters x and y reflect on the
actual parameters a and b (see Figure 7.10).
Copyrighted material
6 Mastering C++
--1552--
±334 — •
Copyrighted material
6 Mastering C++
s
void main{ ) \
( \
> PrintLine( 70) ;
•> PrintLine(1! ' , 1 0 ) ; A'
> PrintLine{1 * ' , 40) ;
> PrintLine(' R ' , ) 5 5 ) ;
Run
RRRRRRRRRRRRRRRRRRRRRRRRRRRRBRRRRRRRRRRRRRRRRRRRRRRRRRR
&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&
Copyrighted material
6 Mastering C++
the memory address of the instruction following the function call, copies the arguments of the
function call onto the stack, and finally transfers control to the specified function. The CPU then
executes the function code, stores the function return value in a predefined memory
location/register, and returns control to the calling function. This constitutes an overhead in the
execution lime of the program. This overhead is relatively large if the time required to execute a
function is less than the context switch time.
C++ provides an alternative to normal function calls in the form of inline functions. Inline
functions arc those whose function body is inserted in place of the function call statement during
the compilation process. With the inline code, the program will not incur any context switching
overhead. The concept of inline functions is similar to macro functions of C. Hence, inline
functions enjoy both the flexibility and power offered by normal functions and macro functions
respectively.
An inline function definition is similar to an ordinary function except that the keyword
inline precedes the function definition. The syntax for defining an inline function is shown in
Figure 7.12..
inline int
sqr( int num)
I
return num*num;
I
K
p-ep-ccesso' ^>
b-sqr(n); - - - > a *5*5; b=n-n;
) J
The significant feature of inline functions is: there is no explicit function call and body is
substituted at the point of inline function call, thereby, the run-time overhead for function linkage
mechanism is reduced. The program square, cpp uses inline function to compute the square of a
number.
Copyrighted material
Chapter 1: Object-Oriented Paradigm
Structured Programming
Structured programming has evolved as a mechanism to address the growing issues of
programming-in-the-large. Larger programming projects consist of large development teams,
developing different parts of the same project independently. The usage of separately compiled
modules (algorithmic decomposition) was the answer for managing large development teams (see
Figure 1.5). Programs consist of multiple modules and in turn, each module has a set of functions
Subprograms
Copyrighted material
Chapter 7: Modular Programming with Functions 68
float c. d;
cout << "Enter two floats <c, d>: ■; cin » c » d;
swapt c, d ) ; / / compiler calls swapt float &a, float &b ) ; cout << "On swapping <c, d>: " << c << " ■
<< d;
Run
Enter two Characters <chl, ch2>: R K
On swapping <chl, ch2>: K R
Enter two integers <a, b>: 5 10
On swapping <a, b>: 10 5
Enter two floats <c, d>: 20.5 99.5
On swapping <c, d>: 99.5 20.5
In the above program, three functions named swap ( ) are defined, which only differ in their argument data
types: char, int, or float. In maint), when the statement swap( chl, ch2 ) ;
is encountered, the compiler invokes the swap ( ) function which takes character type arguments. This decision
is based on the data type of the arguments, (see Figure 7.13).
' / show.cpp: display different types of information with same function •include <iostream.h> void show( int
val ) (
cout « "Integer: ■ « val « endl;
>
void show( double val ) {
cout << "Double: " << val << endl;
>
void showt char *val ) (
cout « "String: " << val << endl;
)
int main ( )
{
showt 420 ) ; / / calls showt int val ) ;
show( 3.1415 ) ; / / calls showt double val ) ;
showt "Hello World\n!" ) ; / / calls showt char *val I : return( 0 ) ;
)
Bun
Integer: 420 Double: 3.1415
String: Hello World
i
Copyrighted material
name. It would, therefore, be more practical to use names such as f indname ( ) and getvidmode ( ) , which
suggest the action they perform.
* C++ docs not permit overloading of functions differing only in their return value. The reason is that it is
always the programmer's choice to inspect or ignore the return value of a function. For instance, the fragment
printf("Hello World!\n"); holds no information concerning the return value of the function printf ( ) .
(The return value in this case is an integer, which states the number of printed characters. This return value is
practically never inspected). Two functions print f ( ) , which would only differ in their return types and hence
they are not distinguished by the compiler.
* Function overloading can lead to surprises. For instance, imagine the usage of statements
show( 0 J ;
show{ NULL ) ;
where there are multiple overloaded functions as in the program show.cpp. The zero could be interpreted here
as a NULL pointer to a char, i.e., a t char*) 0, or as an integer with the value zero. C++ will invoke the function
expecting an integer argument, which might not be what the user expects.
fort int i = 0 ; ( i < size - 1 > USt swapped; i++ )
r
swapped = false;
f or{ int j = 0 ; j < ( s i z e - 1 ) - i; j++ ) i f f a [ j ] >
a[ j * 1 ] ) (
swapped = true;
swap t a[ j ] , a [ j + 1 ] ) ;
)
)
)
void main( void )
(
int a [25] ; int i,
size;
cout « "Program to sort elements..." « endl;
cout « "Enter the size of the integer vector <max-25>:
cin » size;
cout << "Enter the elements of the integer vector..." << endl; fort i = 0; i < size; i++ )
cin » a[i] ; BubbleSort ( a, size ) ; cout «
"Sorted Vector:" « endl; for( i = 0; i < size; 1+
+)
cout « a[ij « "
Hun
Program to sort elements...
Enter the size of the integer vector <max-25>: 5 Enter the elements
of the integer vector. . .
£
I
1
2
Sorted Vector: 2 3
6 8 9
In main ( ) , the statement
BubbleSort ( a, size ) ; invokes the sorting function by passing the address of the array variable a and
the value of the variable size to it. Hence, any modification made to the elements of the airay a will be reflected
in the caller.
7.13 C++Stack
The medium for communication between a caller and the callee is the stack, which is used to store function
parameters, return address, local variables, etc. When the function is invoked, the information such as return
address and parameters, are pushed onto the stack by the function linkage mechanism;
Copyrighted material
70 Mastering C++
block.cpp: illustration of the variables scope in blocks 'include <iostream.h> int main( void )
int i = 144;
cout << "i = " << i;
Reference lo variable k in the main block results in a compile-time error: Undefined symbol k in the
function m a x n O i the variable k is declared inside the nested block within mainO. The memory space for
the variable k is allocated when the execution of the block starts, and released when execution reaches the
end of the nested block. When a variable is accessed, the compiler first checks for its existence in the
current block, and then moves outwards if it does not exist in the current block; this process continues
until the global definition. The function can access the identifiers in the parameter list, the local definitions
and the global definitions (if any).
Auto Variables
By default, all the variables are defined as auto variables. They arc created when the function/block is
entered and destroyed when the function/block is terminated. The memory space for local auto variables is
allocated on the stack. The global auto variables are visible to all the modules of a program, and hence,
they cannot be defined many times unlike the declarations.
Copyrighted material
Chapter 7: Modular Programming with Functions 71
Register Variables
The allocation of CPU (processor) registers to variables, speeds up the execution of a program; memory is
not referred when such variables are accessed. The number of variables, which can be declared as register
are limited (typically two or three), within any function or as global variables (else they are treated as auto
variables). A program that uses register variables executes faster when compared to a similar program
without register variables. It is possible to find out the allocation of register variables only by executing
and comparing the timing performance of the program (perceptible in large programs). It is the
responsibility of the compiler to allot register variables. In case the compiler is unable to do so. these
variables are treated as auto variables. It is advisable to define frequently used variables, such as loop
indices, as register variables. It is illustrated in the program regvar. cpp.
Runl
Enter a string: mahatma
The reverse of the string is: amtaham
Hun2
Enter a string: malavalam
va_start(ap, msg);
while ((arg = va_arg(ap,int)) != 0) { total += arg;
}
cout << msg « total; va_end(ap) ;
}
int main(void) {
sum("The total of 1+2+3+4 is *. 1 , 2 , 3 , 4 , 0 ) ; return 0;
>
Run
The total of 1+2+3+4 is 10
In main ( ) , the statement
sum("The total of 1+2+3+4 is •, 1 , 2 , 3 , 4 , 0 ) ; invokes the variable argument function. The
function sum ( ) is designed such that when a zero valued argument is encountered, it is understood that
no more arguments exists for further processing. Hence, the last argument 0 (zero) in this case, is the end-
of-argument indicator. The programmer has full freedom for selecting suitable end-of-argument indicator.
1 if n = 0 fact(n) =
n * f a c t ( n-1), otherwise
Recursion, as the name suggests, revolves around a function recalling itself. Recursive functions are
those, in which there is atleast one function call to itself (there can be more than one call to itself as in the
tower of hanoi algorithm). The recursive approach of problem solving substitutes the given problem with
another problem of the same form in such a way that the new problem is simpler than the original.
Two important conditions which must be satisfied by any recursive function are:
1. Each time a function calls itself it must be nearer, in some sense, to a solution.
2. There must be a decision criterion for stopping the process or computation.
Recursive functions involve the overhead of saving the return address, formal parameters, local
variables upon entry, and restore these parameters and variables on completion.
Factorial of a Number
Copyrighted material
72 Mastering C++
The program r f a c t . cpp computes the factorial of a number. It has a recursive function f a c t ( ) which
implements the above stated definition of recursion.
The data items enclosed between flower brackets in the above structure declaration are called structure
elements or structure members. Student is the name of the structure and is called structure tag. Note that,
some members of Student structure are integer type and some are character array type. The description of
various components of the structure Student is shown in Figure 8.2.
structure name
struct Student {
int roll_no; char name(251; char branch[15]; int marks;
The individual members of a structure can be variables of built-in data types, pointers, arrays, or even
other structures. All member names within a particular structure must be different. However, member
names may be the same as those of variables declared outside the structure. The individual members
cannot be initialized inside the structure declaration. For example, the following declaration is invalid:
struct Student
{
int roll_no = 0 ; / / Error: initialization not allowed here char name[2 5 ] ; char
branch[151; int marks;
);
The use of the keyword struct in the structure definition statement is optional. The following
siatements create variables of the structure student declared earlier:
struct Student
si; or
Student si ;
Figure 8.4 shows the storage of the members of the structure student.
-A 2 bytes
-A 25 byles
15 bytes
struct Student ( 2 bytes
int roll_no; char
name[ 2 5 ] ; char
branch[15]; int marks; > -
Student s i ;
Copyrighted material
Chapter 7: Modular Programming with Functions 73
The structure variables can be created during the declaration of a structure as follows:
struct Student
{
int roll_no; char
name[25]; char
branch[15] ;
int.marks; } s i ;
In the above declaration, Student is the structure tag, while si is a variable of type Student. If variables of
this structure type are not defined later in the program, then the tag name Student can be omitted as shown
below:
struct
{
int roll_no; char
name[ 2 5 ] ; char
branch[15J; int
marks; ) Si;
It is not a good practice, to have both declaration and definition in the same statement.
Multiple variables of a structure can be created using a single statement as follpws:
struct Student s i , s 3 , s4; or
Student si, s 3 , s 4 ;
All these instances are allocated separate memory locations and hence, each one of them are indepen dent
variables of the same structure type as shown in Figure 8.5.
struct Student {
int roll_no; char
name[ 2 5 1 ; char
branch[15); int
marks;
J ;
Student s l , s 2 , s 3 ;
si s2 s3
Here, structvar is a structure variable and membername is one of its members. Thus, the dot operator
must have a structure variable on its left and a legal member name on its right. Consider the following
statement:
Student s i ;
Each member of the structure variable si can be accessed using the dot operator as follows:
sl.roll_no will access si's roll_no
si.name will access si's name
s i . branch will access si's branch
s i . marks will access si's marks
Copyrighted material
Chapters.* Structures and Unions 241
Run
Enter data for s t u d e n t . . .
Roll Number ? 5 Name ?
Mflflqftla
Copyrighted
material
242 Mastering C++
Branch ? Computer
Total Marks <max-325> ? 290
Student Report
A variable of the structure Student can be initialized during its definition as follows:
Student s i ={ 5 , "Mangala", "Computer", 2 9 0 } ; The initial values for the components of
the structure are placed in curly braces and separated by commas. The members of the variable si, roll_no,
name, branch, and marks are initialized to 5, "Mangala", "Computer", and 290 respectively (see Figure
8.7).
The program days. cpp illustrates the initialization of the members of a structure at the point of a
structure variable definition.
/ / days.cpp: structure members initialization a t the point of definition
•include <iostream.h>
/ / structure declaration
struct date
{
int day; int
month; int year;
);
void main( ) {
date dl = { 14, 4 , 1971 } ; date d2 =
{ 3 , 7 , 1996 } ;
cout << "Birth date: ■;
cout « dl.day «■-"« dl.month «■-•« dl.year; cout « endl «
"Today date: ";
cout « d2.day «"-"« d2.month «■-"« d2.year;
)
Run
Birth date: 14-4-1971
Today date: 3-7-1996
Copyrighted material
242 Mastering C++
The structure to be embedded must be declared before its use. Another way of declaring a nested
structure is to embed member structure declaration within the declaration of a new structure as
follows:
struct Student {
int roll_no; char
name[25]; struct date
{
int day;
int month;
int year; } birthday;
char branch[15]; int marks;
);
The embedded structure date is declared within the enclosing structure declaration. A variable
of type Student can be defined as follows:
Student si;
The year in which the student si was born can be accessed as follows:
si-birthday.year The following are the some of the valid operations on the variable si:
si.roll_no - 5; cin » si. roll_.no; si.
birthday, day = 2; si.birthday.month =
2; si.birthday.year = 1972;
name
Copyrighted material
Chapter 8: Structures and Unions 245
The dot operator accessing a member of the nested structure birthday using the statement
si.birthday.year = 1972; is shown in Figure 8.8. The program student2 . cpp illustrates the declaration,
definition, and processing of nested structure members.
A statement such as
si.date.day = 2 ; / / error
is invalid, because a member of the nested structure must be accessed using its variable name.
/ / Student2.cpp: processing of student data using structures #include <iostream.h> //' structure declaration struct
date
i
int day; int
month; int
year;
Instruct Student
{
int roll.no; char
name[2 5 J ;
struct date birthday; // structure within a structure
char branch[15]; int
marks;
);
void main () {
Student si; / / structure definition
cout << "Enter data for student..." << endl;
cout « "Roll Number ? ";
cin » sl.roll_no; / / accessing structure member
cout « "Name ? "; cin »
si.name;
cout « "Enter date of birth <day month year>: ";
cin >> si.birthday.day » si-birthday.month » si.birthday.year;
cout « "Branch ? ■;
cin >> si.branch;
cout « "Total Marks <max-325> ? "; cin »
si.marks;
cout « "Student Report" « endl;
cout << "-----------------------------" « endl;
/ / process student data
cout « "Roll Number: " « sl.roll_no « endl; cout << "Name: " «
si.name « endl; cout « "Birth day: •;
1
cout<<sl .birthday. day «"-■<< si .birthday .month<<" - "«sl .birthday .year ; cout << endl « "Branch: «
si.branch « endl; cout « "Percentage: " << si .marks*(100.0/325) « endl;
cin >> s[ij.name; cout
<< "Branch ? "; cin »
s[i].branch;
cout << "Total Marks <max-325> ? "; cin
» s [ i ] .marks;
>
cout « "Students Report" « endl;
cout « "---------------------------------" « endl;
// process student data
for( i = 0; i < n; i++ ) (
cout << "Roll Number: " << s[i].roll_.no « endl;
cout << "Name: " « s[i].name << endl;
cout << "Branch: " « s[i].branch « endl;
cout « "Percentage: ■ « s[ij.marks*(100.0/325) « endl;
)
}
Run
How many students to be processed <max-10>: _,
Enter data for student 1... Roll Number ? 5 Name ?
Manga la
Branch ? Computer
Total Marks <max-325> ? 290
Enter data for student 2 . . .
Roll Number ? %
Name ? Shivakumar
Branch ? Electronics
Copyrighted material
Chapter 8: Structures and Unions 245
i
Run
Students Report
Run
Employee Details ...
The name is Rajkumar
The idno is 24914
The salary is 2.83348e*26
Employee Details . . .
The name is
Copyrighted material
Chapter 8: Structures and Unions 245
The idno is 10
The salary is 2.82889e+26
Employee Details . . .
The name is
The idno is -24576
The salary is 9000
The status of the variable e after execuion of each one of the following: 1.s trcpy{e.name, ■Raj kumar");
2. e.idno = 10; and
3. e. salary = 9000;
is shown in Figure 8.14a, 8.14b, 8.14c respectively. Note that, access of non active members will lead to meaningless
values.
Pointer Definition
When a pointer variable is defined, the C++ compiler needs to know the type of variable the pointer points to. The syntax
of pointer variable definition is shown in Figure 9.2.
standard or user defined data type: asterisk followed by a pointer variable name
char, short, int, float, etc.
M DataType * PtrVar,
Dereferencing of Pointers
Dereferencing is the process of accessing and manipulating data stored in the memory location pointed to by a pointer.
The operator * (asterisk) is used to dereference pointers in addition to creating them. A oointer variable is dereferenced
when the unary operator * (in this case, it is called as the indirection opi rator) is prefixed to the pointer variable or pointer
Copyrighted material
Chapter 8: Structures and Unions 245
expression. Any operation that is performed on th; dereferenced pointer directly affects the value of the variable it points
to. The syntax for dereferencing pointers is shown in Figure 9.3.
means of pointers. The power of pointers becomes evident in situations, where indirect access is the
only way to access variables in memory. Figure 9.4 gives a pictorial representation of accessing a
variable using a pointer.
Run
Enter real number <a>: 10.5 Enter real
number <b>: 20.9
After swapping .........
a contains 20.9 b
contains 10.5
Copyrighted material
Chapter 1: Object-Oriented Paradigm 13
Attribute 1
Attribute 2
Attribute N
Attribute 1 Attribute 2
Attribute N
Operation 1 Operation 2
Operation N
Copyrighted material
Ope ation 1
Operation 2
Ope ration
N
Copyrighted material
AccountNumber AccountType
Name Balance
AccountNumber AccountType
Name Balance
Deposit()
Withdraw*) Enquire*)
Figure 1.11: Different styles of representing the account object 1.7 Classes
The objects with the same data structure (attributes) and behavior (operations) are grouped into a class.
All those objects possessing similar properties are grouped into the same unit. The concept of class-ing
the real world objects is demonstrated in Figure 1.12. It consists oflhcPerson class. Vehicle class, and
Polygon class. In the case of Person class, all objects have similar attributes like Name. Age. Sex -md
similar operations like Speak, Listen, Walk. So boy and girl objects are grouped into the Person class.
Similarly, other related objects such as triangle, hexagon, and so on. are grouped into the Polygon class.
Consider the following statements:
float 'sum; char
*name; A statement
such as
sum++; or ++sum;
advances the pointer variable sum to point to the next element. If the pointer variable sum holds the
address 1000, on execution of the above statement, the variable sum will hold the address (1000+4) =
1004 since the size of float is 4 bytes. Similarly, when a statement such as name++; or ++name;
is executed, and if the pointer variable name points to address 2000 earlier, then it will hold the address
(2000*1), since the size of char is one byte. This concept applies to all"arithmetic operations performed
on pointer variables.
When a pointer variable is incremented, its value actually gets incremented by the size of the type to
which it points. For example, let pi be a pointer to an integer defined with the statement
int* pi;
Also, let pi point to the memory location 1020. i.e., the number 1020 is stored in the pointerpi. Now, a
statement which increments pi, such as
pi++;
will add two topi, making it 1022 (assuming that the size of an integer is 2 bytes). This makes pi point
to the next integer. Similarly, the statement
pi--;
will decrement the value of pi by 2. The pointer arithmetic on different types is shown in Table 9.2.
Copyrighted material
cout << "How many bytes to allocate: "; cin »
size;
iff (data = new int[ size ]) )
cout « "Memory allocation success, address = " « data; else
{
cout << "Could not allocate. Bye ...'; exit(1);
;.
delete data;
J
Run1
How many bytes to allocate: 100
Memory allocation success, address = 0xl6be
Hun2
How many bytes to allocate: 30000
Could not allocate. Bye . ..
Note: A request for allocation of 0 bytes returns a non-null pointer. Repeated requests for zero-size
allocations return distinct, non-null pointers.
■ ■ compare the contents of *pa and *pb and assign their address to pbig ift *pa >
'pb )
•pbi
g = pa;
else
"pb i g = pb;
}
void main()
int a. b. 'big;
cout << "Enter two integers: ";
cin >> a >> b;
FindBig( &a, &b, tbig );
cout << "The value as obtained from the pointer: " << *big;
)
Run
Enter two integers: 10. £0.
The value as obtained from the pointer: 20 In
main (). the statement
FindBigt &a, &b, fcbig ); passes a, b, and big variables by address. It assigns the address of the
variable a or b to the pointer variable big. In FindBig (). the statement •pbig = pa;
effectively stores the address of the variable a in the pointer variable big, which is defined in the main()
function.
Copyrighted material
9.9 Array of Pointers
An array of pointers is similar to an array of any predefined data type. As a pointer variable always
contains an address, an array of pointers is a collection of addresses. These can be addresses of ordinary
isolated variables or addresses of array elements. The elements of an array of pointers are stored in the
memory just like the elements of any other kind of array. All rules that apply to other arrays also apply
to the array of pointers.
The syntax for defining an array of pointers is the same as array definition, except that the array name is
preceded by the star symbol during definition as follows: DataType *ArrayName[ARRSIZE\;
Copyrighted material
Salient Features:
□ Clearty explains the language constructs using syntax,
lllustratlons,code segments^nd simple examples.
I
JH Tata McGraw-Hill
Publishing Company Limited
7 West Patel Nagar, New Delhi 110008
Chapter 9: Pointers and Runtime Binding 287
Run
Enter Name: TeiflSWi Enter
another (y/n) ? y_ Enter Name:
Prasad Enter another (y/n) ? y.
Enter Name: PrakflSh Enter
another (y/n) ? y_ Enter Name:
Sudeep Enter another (y/n) ? y
Enter Name: Anand Enter
another ( y / n ) ? n Unsorted
list: Tejaswi Prasad Prakash
Sudeep Anand
Sorted list:
Anand
Prakash
Prasad
Sudeep
Tejaswi
In main ( ) , the statement
person[n] = new char(40); allocates 40 bytes of memory to the (n+ l)lh element and stores its
memory address in the array of pointers to strings indexed by n. The statement
SortByPtrExchange( person, n ) ; invokes the sorting function by passing the array of pointers
and data count as actual parameters. Note that, array is passed to a function just by mentioning its name.
This is equivalent to passing an entire array; the address of the first clement of an array can be used to
access any element in the array by using offset values. The data sorted by SortByPtrExchange ( ) do not
change their physical location (see Figure 9.9). The effect of sorting is seen when strings are accessed
using pointers in a sequence.
Copyrighted material
288 Mastering C++
char "person[100]
unsorted pointers
char -person[100]
Copyrighted material
290 Mastering C++
i
,
j
,
;
290 Mastering C++
i
f
<
!
=
(
cout << "Error: Invalid matrix order for multiplication"; exitt 1 );
}
fort i =
0; i
< m;
i++ J
fort j
= 0;
j<
q; j+
+){
c[i] [j] = 0;
fort k = 0; k < n; k++ )
c[ijljj += a[ij(k] * blfclEj];
}
}
void MatShowt int **a,
int row, int col ) (
int i, j;
fort
i=
0; i
<
row;
i++ )
{
cout
<<
endl;
fort j
= 0; j
<
col;
j++ )
cout
« a[i]
[j] «
"
)
)
v
o
i
d
m
a
i
n
290 Mastering C++
(
)
{
i
n
t
*
*
a
,
*
*
b
,
»
*
c
;
i
n
t
m
,
n
,
p
,
q
;
cout << "Enter Matrix A
details. . . " << endl; cout «
"How many rows ? ";
cin » m;
cout « "How
many
columns ? ";
cin » n;
a
»
M
a
t
A
l
l
o
c
t
m
,
n
)
;
M
a
t
R
e
290 Mastering C++
a
d
t
a
,
m
,
n
)
;
cout << "Enter Matrix B
details.. . " « endl; cout <<
"How many rows ? "; cin » p;
cout «
"How
many
columns
? cin » q;
b = MatAlloct
p, q ) ;
MatReadt b,
p, q ) ; c =
MatAlloct m,
q );
MatMul( a,
m, n, b, p, q, c
);
void my_strcat( char *s2, char *sl )
{
// move end of
string while*
"s2 != '\0' )
s2++; //
append si to s2
whilet *sl !=
"\0* )
*s2 + + = *sl++; *s2 =
'\0'; // copy end of string
)
int my_strcmp( char *sl, char *s2 )
(
// compare as long as they are equal
whilet *sl == *s2 && (*sl != NULL || *s2 != NULL) )
(
S
l
*
*
:
S
2
+
;
}
return *sl - 's2;
>
Run
Enter stringl:
Object Enter
string2: Oriented
Length of stringl: 6
Strings' on concatenation: ObjectOriented
String comparison using ...
Library function: -16
User's function: -16
Pointer variables, like other variables are also allocated memory whenever they are defined. The
size of the memory allocated (in bytes) to a pointer variable depends on whether the pointer just
holds the offset part of the address, or both the segment and offset values. The memory model in
wnich the program is compiled also influences the size of the pointer variables used in that
program. C++ compilers (such as Borland or Microsoft C++) running under DOS environment
support six different memory models, each of which determines the amount of memory allocated
to the program's data and code (see Table 9.3).
Normally, all pointers defined in a program in the small model contain only the offset part of
the address. Such pointers are known as near pointers, for which two bytes of memory are
allocated. The use of near pointers limits the programmer to access only those memory locations,
which lie within a single segment only. (The maximum size of a segment is 64 KB). This
limitation can be overcome by the use of pointers, which arc capable of holding both the segment
as well as the offset part of an address. Such pointers arc called far pointers, for which four bytes
of memory is allocated. It is possible to access any memory location, using far pointers. The far
pointers can be defined (even in a small memory model) by using the keyword far as follows:
int far "ifarptr; // defines a far pointer to int
This declaration is similar to the structure declaration in C. It enables the creation of the class
variables called objects. For example, the following statements,
account savings_account;
account current_account;
account FD_account; create instances of the class account. They define savings_account,
current_account. and FD_account as the objects of the class account. From this, it can be inferred
that, the account class groups objects such as saving account, current account, etc. Thus, objects
having the same structural and behavioral properties are grouped together to form a class.
Each class describes a possibly infinite set of individual objects; each object is said to be an
instance of its class and each instance of the class has its own value for each attribute but shares
the attribute name and operations with other instances of the class. The following points on
classes can be noted:
♦ A class is a template that unites data and operations.
♦ A class is an abstraction of the real world entities with similar properties.
♦ A class identifies a set of similar objects.
♦ Ideally, the class is an implementation of abstract data type.
Struct
first
LIST '
data i
I-------1
: "next Figure 9.14: Linked list with self-referential structures
l
290 Mastering C++
return( first ) ;
m
a
i
n
(
)
{
LIST *list = NULL; / / list is
empty int choice, data;
set_new_handler t 0 ) ; / / makes new to return to NULL i f it fails cout <<
"Linked-list manipulations program...\n";
w
h
i
l
e
(
l
)
(
cout << "List operation, 1- Insert, 2-Display, 3-Delete, 4-Quit: "; cin >>
choice; switch( choice ) (
case 1:
cout << "Enter data for node to be created: * ; cin >> data;
list = InsertNode( data, list ),-
b
r
e
a
k
;
c
a
s
e
2
:
cout << "List contents: ";
DisplayList( list ) ;
b
r
e
a
k
;
c
a
s
e
3
:
cout << "Enter data for node to be delete: "; cin » data;
list = DeleteNode( data, list ) ;
break; case 4:
cout « "End of Linked List Computation ! ! . \ n " ; return; default:
290 Mastering C++
Another important point to be noted is that, avoid storing the address of a variable or an
object into a pointer in the inner block, and using the same in the outer block. The program wild4
. cpp illustrates the wild pointer accessing garbage location.
"
p
i
;
C
char name I] =
"Savithri "; pi = name;
J
// do some processing here
cout « "Name = " << pi << endl;
}
Run
Name = SavithQS!
In main f), the statement
cout « "Name = " « pi << endl; accesses the data pointed to by the pointer variable pi.
The variable pi is assigned to point to the variable name defined within an inner block. When the
execution of this block is completed, all the variables are destroyed and hence, accessing of data
stored in the variable name becomes invalid data. In some situation, the programs might execute
properly, but they may corrupt other program's data and lead to system crash.
The above discussion also holds good for pointer to objects. Like variables, whenever objects
goes out of scope, they are destroyed. Referencing such objects is like accessing invalid-data
variable and hence, such reference should be avoided.
Review Questions
9.1 What are pointers ? What are the advantages of using pointers in programming ? Explain
addressing mode required to access memory locations using pointers.
9.2 Under what situations, the use of pointers is indispensable ?
9.3 Write a program to print address of the variables defined by the following statement:
int a, b =
10; float
c = 2, d;
9.4 Explain the syntax for defining pointer variables. How different arc these from normal
variables?
9.4 What is dereferencing of pointers ? Write a program to dereference the pointer variables
in the following statements (print value pointed to by pointer variables):
int *a; double
*b; a = &i; b
= &f;
9.6 What are the differences between passing parameters by value and by pointers ? Give
examples.
Classes are the basic language construct of C++ for creating the user defined data types. They
arc syntactically an extension of structures. The difference is that, all the members of structures
are public by default whereas, the members of classes are private by default. Class follows the
principle that the information about a module should be private to the module unless it is specifically
declared public.
contain not only data but also functions. The functions are called member functions and define
the set of operations that can be performed on the data members of a class. Thus, a class can be
described as a collection of data members along with member functions. This property of C++,
which allows association of data and functions into a single unit is called encapsulation.
Sometimes, classes may not contain any data members or member functions (and such classes
are called as empty classes). The syntax of a class specification is shown in Figure 10.2.
Na
me
of
the
user
defi
ned
clas
s
Keyword
class
ClassNa
me {
// body of a class
The class specifies the type and scope of its members. The keyword class indicates that the
name which follows (ClassName) is an abstract data type. The body of a class is enclosed within
the curly braces followed by a semicolon—the end of a class specification. The body of a class
contains declaration of variables and functions, collectively known as members. The variables
declared inside a class are known asdata members, and functions are known as member functions.
These members are usually grouped under two sections, private and public, which define the
visibility of members.
The private members are accessible only to their own class's members. On the other hand,
public members arc not only accessible to their own members, but also from outside the class.
The members in the beginning of class without any access specifier are private by default.
Hence, the first use of the keyword private in a class is optional. A class which is totally private is
hidden from the external world and will not serve any useful purpose.
The following declaration illustrates the specification of a class called s tudent having rol l_no
and name as its data members: class student {
int roll_no; // roll number
char name! 20 J; // name of a student
public:
Chapter 10: Classes and Objects 315
int rollno
char name[20]
setdata()
outdata()
The name of data and member functions of a class can be the same as those in other classes; the members of
different classes do not conflict with each other. Essentially, a class identifies all the data members associated
with its declaration. The following example illustrates this concept: class Person {
private:
char name[20]7
int age;
The data member name appears in the student class and in the Person class declarations, but their scope is
limited to their respective classes. However, more than one class with the same class-name in a program is an error,
whether the declarations are identical or not. A class can have multiple member functions (but not data members)
with the same name as long as they differ in terms of signature ; this feature is known as method overloading.
Like structures, the data members of the class cannot be initialized during their declaration, but they can be
initialized by its member functions as follows:
class GeoObject {
float x, y = 5; // Error: data members cannot be initialized here void SetOriginO // set point
to origin
{
x = y = 0.0;
)
};
The data members x ory of the class GeoObject cannot be initialized at the point of their declaration, but, they
can be initialized in member functions as indicated in the SetOrigin () member function.
1/
class ClassName ObjectName, ..-;
Copyrighted material
C
h
a
p
t
e
r
1
:
O
b
j
e
c
t-
O
ri
e
n
t
e
d
P
a
r
a
d
i
g
m
17
Data abstraction is supported by several other modern programming languages such as Smalltalk.
Ada. etc. In these languages, and in C++ as well, a programmer can define a new abstract data type by
specifying a data structure, together with the operations permissible on that data structure as shown in
Figure 1.14. The important feature o*"C++. the class declaration, allows encapsulation and creation ol
abstract data types.
The use of encapsulation in protecting the members (data and code) of a class from unauthorized
access is a good programming practice; it enforces the separation between the specification and imj.
lementation of abstract data typos, and it enables the debugging of programs easily.
1.10 Inheritance
Inheritance is the process, by which one object can acquire the properties of another. It allows the
declaration and implementation of one class to be based on an existing class. Inheritance is the most
promising concept of OOP, which helps realize the goal of constructing software systems from reusable
parts, rather than hand coding every system from scratch. Inheritance not only supports reuse across
systems, but also directly facilitates extensibility within a given system. Inheritance coupled with
polymorphism and dynamic binding, minimizes the amount of existing code to be modified while
enhancing a system.
To understand inheritance, consider the simple example shown in Figure 1.15. When the class Child,
inherits the class Parent, the class Child is referred to as derived class (sub-class), and the class Parent as a
base class (super-class). In this case, the class Child has two parts, a derived part and an incremental part.
The derived part is inherited from the class Parent. The incremental part is the new code written
specifically for the class Child. In general, a feature of Parent may be renamed, re-implementcd.
duplicated, voided (nullified), have its visibility status changed or subjected to almost any other kind of
transformation when it is mapped from Parent to Child. The inheritance relation is often called the is-a
relation. This is because when the class Child inherits the base class Parent, it acquires all the properties
of the Parent class. It can also have its own properties, in addition to those acquired from its Parent. This
is an example of single inheritance; the child class has inherited properties from only one base class.
The inheritance relation is often used to reflect the elements present in an application domain. For
example, consider a rectangle which is a special kind of polygon as shown in Figure 1.16. This relation-
ship is easily captured by the inheritance relation When the rectangle is inherited from the polygon, it
Copyrighted material
In mainO, the statements
student si; // first object/variable of class student student s2; // second
object/variable of class student create two objects called si and s2 of the student class. The
statements
si.setdata( 1, "Tejaswi" ); //object si calls member function setdata
s2.setdata( 10,"Rajkumar" ); //object s2 calls member function setdata
initialize the data members of the objects si and s2. The object si's data member roll_no is assigned 1
and name is assigned Tejaswi. Similarly, the object s2's data member roll_no is assigned 10 and
name is assigned Rajkumar.
The statements
si.outdata(); // object si calls member function outdata
s2.outdata(); // object s2 calls member function outdata
call their member outdata () to display the contents of data members namely, rol l_no and name of
student objects si and s2 in succession. Thus, the two objects si and s2 of the class student have different
data values as shown in Figure 10.7.
Client-Server Model
In conventional programming languages, a function is invoked on a piece of data (function-driven
communication), whereas in an OOPL (object-oriented programming language), a message is sent to an
object (message-driven communication) i.e., conventional programming is based on function abstraction
whercrs, object oriented programming is based on data abstraction.
The object accessing its class members resembles a client-server model. A client seeks a service
whereas, a server provides services requested by a client. In the above example, the class student
Similar to the real world objects. OO objects also have a life cycle. They can be created and de-
stroyed automatically whenever necessary. Communication between the objects can take place as long as
they are alive (active). Communication among the objects takes place in the same way as people pass
messages to one another. The concept of programming with message passing model is an efficient way of
modeling real-world problems on computers.
student s2;
Client
Information
Message
Copyrighted material
A message for an object is interpreted as a request for execution of a procciurc. The subroutine or
function is invoked soon after receiving the message and the desired results are generated within an
object. It comprises the name of an object, the name of a function, and the information to be sent to an
object.
public:
in
t
b;
void myfunco--------------- Member function
(
// body of a function
)
};
The program datel. cpp demonstrating the definition of member functions with the class specification
of the date class. It has private data members day, month, year and inline member functions, set () which
initializes data members and show {), which displays the value stored in the data members.
// datel.cpp: date class with member functions defined inside a class ♦include <iostream.h> class date {
private:
int day;
int month;
int
year;
public:
void set( int Dayln, int Monthln, int Yearln ) {
day = Dayln;
month = Monthln;
year = Yearln;
)
void
show() {
cout << day << "-" << month << "-" << year << endl;
}
J i inform the compiler to treat the member functions set and show as inline functions. The method
of invoking inline member functions is the same as those of the normal functions. In main (J, the
statements
d l . s e t t 2 6 , 3 , 1958 )
; d2.show( ) ;
will be replaced by the function itself since the function is an inline function. Note that, the inline
qualifier is tagged to the inline member function at the point of its definition.
The feature of inline member functions is useful only when they are short. Declaring a function
having many statements as inline is not advisable, since it will make the object code of a program
very large. However, some C++ compilers judge (determine) whether a given function can be
appropriately sized to inline expanded. If the function is too large to be expanded, it will not be
treated as inline. In this case, declaring a function inline will not guarantee that the compiler will
consider it as an inline function.
Copyrighted material
When to Use inline Functions
The following are simple thumb rules in deciding as to when inline functions should be used:
In the above program, the data fields ModelNum. PartNum, and cose of the class part cannot be
accessed by direct references using pi.ModelNum, pi.PartNum, and pi.cost respectively. When a class is
used, its declaration must be available. Thus, a user of the class is presented with a description of the
class. The internal details of the class, which are not essential to the user arc not presented to him. This is
the Concept of information hiding or data encapsulation. As far as the user is concerned, the knowledge of
accessible data and member functions of a class is enough. These interfaces, usually called the user
interface methods, specify their abstracted functionality. Thus, to the user, a class is like a black box with
a characterized behavior.
The purpose of data encapsulation is to prevent accidental modification of information of a class. It
is achieved by imposing a set of rules—the manner in which a class is to be manipulated and the data
and functions of the class can be accessed. The following are the three kinds of users of a class:
♦ A class member, which can access all the data members and functions of its class.
♦ Generic users, which define the instance of a class.
♦ Derived classes, which can access members based on privileges.
Each user has different access privileges to the object. A class differentiates between access privi -
leges by partitioning its contents and associating each one of them with any one of the following
keywords:
♦ private
♦ public
♦ protected
These keywords arc called access-control specifiers. All the members that follow a keyword (upto another
keyword) belong to that type. If no keyword is specified, then the members are assumed to have private
privilege. The following specification of a class illustrates these concepts:
class
PiggyBank {
int Money; void Display{) Private by default Private by
default
}
private: int AccNumber;
Private by declaration
public:
int code; Public Public
void SetData(int a, int b) {
}
protected:
int PolicyCode; void GetPolicyCode{) { Protected Protected
Copyrighted material
)
In (he above declaration, the members Money, AccNumber, and Display {) will be
of type private; the members code and SetData () will be of typepublic; and the
members PolicyCode and GetDataO will be of type protected.
Data hiding is mainly designed to protect well-intentioned programmers from honest mistakes. It
protects access to the data according to the design decision made while designing a class. Programmers
who really want to figure out a way to access highly protected data such as private, will find it hard to do
so even by accident. There are mechanisms to access even private data using friends, pointer to members, etc.
from outside the class.
Private Members
The private members of a class have strict access control. Only the member functions of the same class
can access these members. The private members of a class are inaccessible outside the class, thus,
providing a mechanism for preventing accidental modifications of the data members. It is illustrated in
Figure 10.12. Strictly speaking, information hiding is implemented only partially, the private members
can still be accessed. Access control in C++ has the objective of reducing the likelihood of bugs and
enhancing consistency. Since the basic intention of declaring a class is to use it in a program, the class
should have atleast one member that is not private.
class Person
{ ^^J* Note: colon here
private : ^ access specifier
// private members
);
Person pi;
a=pl. age; X cannot access private data
pi. getage {); X cannot access private function
Figure 10.12: Private members accessibility
rhe following example illustrates the situation when all the members of a class are declared as private:
class Inaccessible <
int x;
void Display()
(
cout « "\nData
} }
;
void main ()
i
// Creating an object. //
Inaccessible objl; objl.x = 5;
Error: Invalid access. //
objl.Display{J ;
Error: Invalid access.
)
Copyrighted material
Table 10.1: Visibility of class members
class C;
Member (unctions of class C public:
can access both private and ✓
public members Object of class C can access
only public members of C
C objc;
private: int
a; void
fl()
protected
: int
b;
voi
d
f2
public:
int c;
void
£3 0 {
//can refer to data member a, b, c and functions f l , f2, and f ?
)
int * v ; / / pointer o
to a veotor i n t s z ; i
/ / s i z e o f a vector d
public:
s
void VectorSizet int s i z e ) / / allocate memory
h
dynamically { o
sz = size; w
v = new int [ size ] ; / / dynamically allocate vector _
} s
v u
o m
i (
d )
;
r
e
a
d
(
)
;
Copyrighted material
void release( ) / / release memory allocated { vl.release(
delete v ; ); / / free
) vector
}' resources
void vector: : read ( ) J
f o r t int i = 0 ; i Run
< sz; i++ ) { How many
cout « 'Enter v e c t o r ! ■ « 1 « ■ ] ? " ; cin > > v ( i ] ; elements are
J there i n
) v e c t o r : 5_
void Enter vector[ 0
J?1
vector:
Enter vector[ 1
:show_s
)?2
um() (
Enter vector[ 2
int sum = 0 ;
]?1
f o r t int i = 0 ; i < s z ; i + + )
Enter
sum + =
vector! 3 ] ?
v[i] ; cout «
"Vector Sum = " 4
« sum; Enter
vector! 4 ]
? 5_
v
Vector Sum ~
o 15
i
d
m
a
i
n
(
)
{
v
e
c
t
o
r
v
l
;
i
n
t
c
o
u
n
t
;
cout < < "How many elements are there i n vector: " ; c i n > >
count;
vl.VectorSize{ count ) ; / / set vector s i z e
vl.read( ) ;
vl. show_sum { ) ;
Copyrighted material
Copyrighted
material
In main (), the statement
vector vl ;
creates an object vl of the class vector and the statement
vl.VectorSize( count ); // set vector size allocates the required amount (specified by the
parameter count) of memory, dynamically for vector elements storage. The last statement
vl.release();
releases the memory allocated to the pointer data member v of the vector class. The operation of
dynamic allocation of memory to data members can be at best realized by defining constructor and
destructor functions. (More details can be found in the chapter Object Initialization and Cleanup).
Copyrighted material
void read()
{
cout « "Enter feet: "; cin >> feet; cout « "Enter
inches: "; cin » inches;
)
Account number is: 20
Balance is: 7 5 0 . 5
How much money is to be transferred from acc3 to accl: 200
Updated Information about accounts...
Account number i s : 1
Balance is: 300
Account number i s : 10
Balance i s : 0
Account number i s : 20
Balance is: 550.5
In main ( ) . the statement
acc3-MoneyTransfer( accl, trans_money ) ; transfers the object accl by reference to the
member function MoneyTransf er ( ) . It is to be noted that when the MoneyTransf er ( ) is
invoked with accl as the object parameter, the data members of acc3 are accessed without the use
of the class member access operator, while the data members of accl are accessed by using their
names in association with the name of the object to which they belong. An object can also be
passed to a non-member function of the class and that can have access to the public members only
through the objects passed as arguments to it.
private:
float real; float // real part of complex number
imag; // imaginary part of complex number
Copyrighted material
342 Mastering C++
class X classY
private:
protected:
data or function
class Z
fzl()
functionl()
friend of X
fz2()
The function declaration must be prefixed by the keyword friend whereas the
function definition must not. The function could be defined anywhere in the
program similar to any normal C++ function. The functions that are declared
with the keyword friend are called friend functions. A function can be a friend to
multiple classes. A friend function possesses the following special
characteristics:
/ ' friend function of class one and two int
add_both( one a, two b )
{
return a.datal + b.data2; // a.datal and b.data2 are private
}
void main ( )
(
one
a;
two
b;
a.setdata( 5 ) ; b.
setdata( 10 > ;
cout << "Sum of one and two: " << add_both( a, b ) ;
}
Copyrighted material
342 Mastering C++
Run
Sum of one and two: 15
The above program, contains two classes named one and two. To allow the normal function add_both()
to have an access to private data members of objects of these classes, it must be declared as a friend
function. It has been declared with the friend keyword in both the classes as:
friend int add_both( one a, two b ) ; This declaration can be placed either in the private or the
public section of the class.
An object of each class has been passed as an argument to the function add_both{). Being a friend
function, it can access the private members of both classes through these arguments.
Observe the following declaration at the beginning of the program
class two; / / advance declaration like function prototype It is necessary, since a class cannot be
referred until it has been declared before the class one. It informs the compiler that the class two's
specification will appear later.
Though friend functions add flexibility to the language and make programming convenient in certain
situations, they are controversial; it goes against the philosophy that only member functions can access a
class's private data. Friend functions should be used sparingly. If a program uses many friend functions, it
can easily be concluded that there is a basic flaw in the design of a program and it would he better to
redesign such programs. However, friend functions are very useful in certain situations. One such example
is when a friend is used to increase the versatility of overloaded operators, which will be discussed in the
chapter Operator Overloading.
Friend functions are useful in the following situations:
♦ Function operating on objects of two different classes. This is the ideal situation where the friend function
can be used to bridge two classes.
♦ Friend functions can be used to increase the versatility of overloaded operators.
♦ Sometimes, a friend allows a more obvious syntax for calling a function, rather than what a member
function can do.
Friend Classes
Friend functions permit an exception to the rules of data encapsulation. The friend keyword allows a
function, or all the functions of another class to manipulate the private members of the original class. The
syntax of dcclaring/rii/u/ class is shown in Figure 10.19.
Copyrighted material
346 Mastering C++
class boy {
private: - ' private specifier
int income1;
int income2;
public: - public specifier
int gettotalO
{
return incomel * income2;
}
friend class girl; //class girl can access private members
};
class girl {
/ / all the members of class girl can access attributes of boy
public: private data of
int girlfunctboy bl) ^—class boy
result = bl.incomel+bl.income2; return
result;
* private data of
™ld show{) /classboy
boy bl; *
cout « "Incomel: " << bl.incomel; / / private data of boy
>
All the member functions of one class can be friend functions of another class. The program
friend2 .cpp demonstrates the method of bridging classes using friend class.
/ / friend2.cpp: classgirl is declared as a friend of class boy #include <iostream.h>
/ / forward declaration of class girl; is optional
class boy
t
private: / / private members
int incomel;
int income2;
public:
void setdata ( int inl, int in2 ) {
incomel = inl;
income2 = in2;
)
friend class girl; / / class girl can access private data
11
Object Initialization and Cleanup
Copyrighted material
346 Mastering C++
bag. p u t ( item ) ;
cout « "Items in Bag: " ;
bag.s h o w t ) ;
}
)
Run
Enter Item Number to be put into the bag <0-no item>: .1 Items in
Bag: 1
Enter Item Number to.be put into the bag <0-no item>: 2 Items in
Bag: 1 3
Enter Item Number to be put into the bag <0-no item>: 2. Items in
Bag: 1 3 2
Enter Item Number to be put into the bag <0-no item>: 4 Items in
Bag: 1 3 2 4
Enter Item Number to be put into the bag <0-no item>: 0.
Copyrighted material
346 Mastering C++
Run
constructor of class Test called (globalobject G)
constructor of class Test called (objectX in main())
mainO function
constructor of class Test called (object L in func())
here's function funcO
The output produced by the program is as desired (see Run - the text in parentheses indicates comment). The
program shows how a class Test is defined, which consists of only one function: the constructor. The constructor
performs only one action; a message is printed. The program contains three objects of the class Test: first a global
object, second a local object in main ( ) , and thirtf arother local object in func ( ) .
Chapter 1: Object-Oriented Paradigm 23
gradually to programming in C+ +, in the first step just feeding their existing C code through the C* + translator and checking if
some small modifications would be necessary". However, some consider this as a disadvantage. They claim that an abrupt
change of paradigm is necessary to make programmers think in an object-oriented fashion.
C++ is evolved from a dialect of C known as C with Classes as a language for writing effective event-driven
simulations. Several key ideas were borrowed from the Simula67 and ALGOL68 programming languages. The heritage
of C++ is shown in Figure 1.20. Earlier version of the language, collectively known as "C with Classes" has been in use
since 1980. It lacked operator overloading, references, virtual functions, and all these are overcome in C++. The name
C++ (pronounced as C plus plus) was coined by Rick Mascitti in the summer of 1983. The name signifies the
evolutionary nature of the changes from C. "++" is the C increment operator. The slightly short name C+ is a syntax
error; it has also been used as the name of an unrelated language. Connoisseurs of C semantics find C++ inferior to ++C
The language is not called D, because it is an extension of C, and does not attempt to remedy the problems by removing
features.
Simula 67 Algol 68
* N
C with AT&T C++
* Classes"
AT&T
C
Copyrighted material
346 Mastering C++
The C++ language corrects most of the deficiencies of C by offering improved compile-time type checking and
support for modular and object-oriented programming. Some of the most prominent features of C++ are classes, operator
and function overloading, free store management, constant types, references, inline functions, inheritance, virtual functions,
streams for console and file manipulation, templates, and exception handling.
In C++, both attributes (data) and methods (functions) are members of a class. The members must be declared either
as private or public. Public members can be accessed by any function; private members can only be accessed by methods
of the same class. C++ has a special constructor function to initialize new instances and a destructor function to perform
necessary cleanup when an object is to be destroyed. C++ provides three kinds of memory allocation for objects: static
(preallocated by the compiler in fixed global memory); automatic (allocated on the stack) anddynamic (allocated from a
heap). Static storage is obtained by defining a variable outside any function using the static keyword . Local variables
within functions normally use automatic storage. Dynamic storage is allocated from a heap on an explicit request from
the programmer and it must be explicitly released since, standard implementations of C++ do not have a garbage
collector.
The superclass of a class is specified as a part of class declarations. A superclass is known as base crass and a
subclass is known as derived class. Attributes once declared in the superclass, which are inherited by its subclasses, need
not be repealed. They can be accessed from any subclass unless they assigns 1.5 toreal_in and 2.0 to imag_in. If the
actual parameter is explicitly specified, it overrides the default value. As stated earlier, the missing arguments must be
the trailing ones. The invocation of a constructor with default arguments while creating objects of the class complex is
shown in Figure 11.6.
class complex {
public: - ■ ►complex () ;
complex(float real_in,float imag_in=6.0);
complex cKl.5,2.0);------------------------....................
complex c2(2.2);-------------------------------------------
complex c3;
Suppose the specification of the constructor complex (float, float) is changed to, complex! float real_in = 0.0, float
imag_in = 0 . 0 ) in the above program, it causes ambiguity while using a statement such as, complex cl;
The confusion is whether to call the no-argument constructor,
complex::complex( ) or the two
argument default constructor
complex::complex( float = 0.0, float = 0.0) Hence, such a specification should be avoided. If no constructors
are defined, the compiler tries to generate a default constructor. This default constructor simply allocates storage to
build an object of its class. A constructor that has all default arguments is similar to a default (no-argument) constructor,
because it can be called without any explicit arguments. This may also lead to errors as shown in the following program
segment:
class X {
int value; public:
X()
{
value=0;
)
X(int i=0) (
value=i;
)
);
-vector{) / / destructor
{
delete v; / / release vector memory
)
void readO ; void
show_sum<);
};
void vector: : read ( )
{
for( int i = 0; i < sz; i++ ) (
cout « "Enter vector! ■ « i « ■ ] ? ■ ; cin >> v[i J ;
}
)
void vector::show_sum()
{
int sum = 0;
for( int i = 0; i < sz; i++ )
sum += v ( i J ; cout << "Vector Sum = " «
sum;
>
void main ( ) {
int count;
Copyrighted material
346 Mastering C++
cout « "How many elements are in the vector: " ; cin » count;
// create an object of vector class and compute sum of vector elements
vector vl{ count ) ;
vl.readt) ;
vl.show_sum{);
}
Run
How many elements are in the vector: 5_
Enter vector! 0 ] ? 1
Enter vector! 1 1 ? 2.
Enter vector! 2 ) ? 2
Enter vector! 3 ] ? 4
Enter vector! 4 ] ? 5_
Vector Sum = 15
Run
Copy constructor invoked vector vl: 1, 2,
3, 4 , 5, vector v2: 1, 2, 3, 4 , 5, vector
v2: 1, 2 , 3, 4 , 5,
A copy constructor copies the data members from one object to another. The function also prints the message (copy
constructor invoked) to assist the user in keeping track of its execution. The copy constructor takes only one argument,
an object of the type vector, passed by reference. The prototype is
vectorf vector &v2 ) ; It is essential to use a reference in the argument of a copy constructor. It should not be
passed as a value; if an argument is passed by value, its copy constructor would call itself to copy the actual parameter
to the formal parameter. This process would go on-and-on until the system runs out of memory. Hence, in a copy
constructor, the argument must always be passed by reference, preventing creation of copies. A copy constmctoi also
gets invoked when the arguments are passed by value to functions, and when values arc returned from functions. If an
object is passed by value, the argument on which the function operates is created using a copy constructor. If an object
is passed by address, or reference, the copy constructor would not be invoked, since, in such a case, copies of the objects
need not be created. When an object is returned from a function, the copy constructor is invoked to create a copy of the
value returned by the function.
Copyrighted material
346 Mastering C++
}
read( ) (
//read members of Student class's object including 'birthday' cin >> roll_no;
Review Questions
Copyrighted material
346 Mastering C++
11.1 What are constructors and destructors ? Explain how they differ from normal functions.
11.2 W^hat are the differences between default and parameterized constructors ?
11.3 What are copy constructors and explain their need ?
11.4 What is the order of construction and destruction of objects ?
11.5 What are read-only objects ? What is the role of constructor in creating such objects ?
11.6 State which of the following statements are TRUE or FALSE. Give reasons.
Figure 12.2). The program ptrobjl.cpp illustrates the definition of pointers to objects and their usage in accessing
members of a class.
class XYZ {
private:
int a ;
int b; public:
int c , d ;
int fund ( ) ;
};
XYZ objl; XYZ *ptr;
ptr->funcl();
-someclass()
void showt)
);
void main (void) {
someclass *ptr; // define a pointer to object of class someclass
someclass objectl; // object of type someclass created statically ptr = fcobjectl;
cout << "Accessing object through objectl.show()...' << endl;
The program ptrob j 2 . cpp illustrates the binding of dynamic objects' address to a pointer vari-
able. The pointer defined is initialized with the address returned by the new operator, which actually
creates the object.
/ / ptrobj2.cpp: pointer to object, pointing to dynamically created objects # include <iostream.h> class
someclass
(
public:
int datal; char
data2;
someclass( )
(
cout « "Constructor someclass{ ) is invokedNn'; datal = 1, data2 = * A ' ;
)
-someclass{ ) {
cout « "Destructor -someclass( ) i s invokedXn";
>
void show() {
cout « "datal = " « datal;
cout « " data2 = " « data2 « endl;
Copyrighted material
346 Mastering C++
)
};
void main (void) {
someclass *ptr; / / define a pointer to object of class someclass
cout « "Creating dynamic o b j e c t . . . " « endl;
ptr = new someclass; / / object created dynamically
cout « "Accessing dynamic object through p t r - > s h o w ( ) . . . " « endl;
ptr->show();
cout < < "Destroying dynamic o b j e c t . . . " « endl;
delete ptr; / / object destroyed dynamically
)
Run
Creating dynamic o b j e c t . . .
Constructor someclass ( ) is invoked
Accessing dynamic object through p t r - > s h o w ( ) . . .
datal = 1 data2 = A
Destroying dynamic object...
Destructor -someclass( ) is invoked
In main { ) , the statement
ptr = new someclass; / / object created dynamically creates the nameless object of the class
someclass dynamically and assigns its address to the object pointer ptr. It executes the constructor of
the class someclass automatically during the creation of dynamic objects. The default argument
constructor initializes the data members datal and data2.
/ / refobj.cpp: reference co dynamic objects
•include <iostream.h>
♦include <string.h>
class student
{
private:
int roll_no; / / roll number
char name[ 20 ] ; / / name of a student
public:
/ / initializing data members void setdata( int roll_no_in,
char *name_in ) (
roll_no = roll_no_in; strcpyf
name, name_in ) ;
)
/ / display data members on the console screen void
outdata f) (
cout « "Roll No = ■ « roll_no « endl; cout « "Name
= " « name « endl;
)
);
void main ( )
{
student &sl = "(new student); / / reference to a dynamic object s i . setdata( 1 , "Savithri" ) ;
si.outdata{ ) ;
student &s2 = *{new student); / / reference to a dynamic object s2.setdata( 2 , "Bhavani" ) ;
s 2 . outdata( ) ; student s 3 ;
s 3 . setdata( 3 , "Vani" ) ;
student &s4 = s 3 ; / / reference to static object s 3 .outdata ( ) ;
s4.outdata( ) ;
}
Bun
Roll No = 1
Nam = Savithri
e
Roll No = 2
Nam = Bhavani
e
Roll No = 3
Nam = Vani
e
Roll No = 3
Nam = Vani
e
In main ( ) , the
statement
Copyrighted material
346 Mastering C++
student &sl = "(new student); creates a dynamic object of the class student and binds it to the reference
variable si. The expression * (new student) creates a dynamic object. The memory allocated to such objects cannot l>c
12.4 Array of Objects
C++ allows the user to create an array of any data type including user-defined data types. Thus, an array of variables of
a class data type can also be defined, and such variables are called an array of objects. An array of objects is often used
to handle a group of objects, which reside contiguously in the memory. Consider the following class specification:
class student
(
private:
int roll_no; / / roll number
char namef 20 ] ; / / name of a student
public:
void setdatat int roll_no_in, char *name_in ) ; void outdata( ) ;
)i
The identifier student is a user-defined data type and can be used to create objects that relate to students of different
courses. The following definition creates an array of objects of the student class:
student science[10J; / / array of science course students student medical[ 5 ] ; / / array of medical course students
student engg[25]; / / array c f engineering course students The array science contains ten objects, namely
science[ 0 ] , . . . science[ 9 ] of type student class, the medical array contains 5 objects and the engg array contains 25
objects.
An array of objects is stored in the memory in the same way as a multidimensional array created at compile time.
The representation of an array of engg objects is shown in Figure 12.5. Note that, only the memory space for data
members of the objects is created; member functions are stored separately and shared by all the objects of student class.
engg[1]
roll_no name
An array of objects behaves similar to any other data-type array. The individual element of an array of
objects is referenced by using its index, and member of an object is engg[24] accessed using the dot operator
For instance, the statement
engg[i).setdata( 10, "Rajkumar" ) ; sets the data members of the ith element of the array engg. Similarly, the
statement
engg[i].outdata( ) ;
will display the data of the ith element of the array engg[i]. The program student 1. cpp illustrates the use of the array of
objects.
Copyrighted material
346 Mastering C++
Km
Create student object ( y / n ) : y
Copyrighted material
Chapter 1: Object-Oriented Paradigm 27
mer must switch from designing programs based on actions to designing programs around data types and
their interactions.
The designer of C++. Bjarne Stroustrup. recommends that the shift from C to C++ should be a gradual
one. with programmers learning the improvements a small step at a time. With C++, quite often, people, as a
first exercise, write a string class and as a second exercise, try to implement a graphics system. That is very
challenging and might be good for a professional programmer, but it's not the best way of teaching an
average student programmer. What we need is an environment that has a very good string class that you can
take apart and look at one which has a very nice graphics system, so that you never care about MS-windows
or X-windows again, unless you absolutely want to. So, the two components needed to start OO
programming are an environment and a library supporting resuability.
Copyrighted material
Chapter 1: Object-Oriented Paradigm 27
a
=
z;
re
tu
rn
z;
)
);
void main ( )
{
X Obj;
int X : : * i p ; / / pointer to data member
ip = & X : : a ; / / address of data member a i s assigned to pointer / / access through
object obj.*ip = 10;
cout « "a in obj, after obj.*ip = 10 is " « obj.*ip « endl; X *pobj; / / pointer to object of
the class X pobj = &obj;
/ / access through object
pointer pobj->*ip = 10;
cout « "a in obj, after pobj->*ip = 10 is ■ « pobj->*ip « endl; int ( X : : * p t r _ i n i t )
( i n t ) ; / / pointer to member function ptr_init = & X : : i n i t ; / / pointer to member
function i n i t O / / access through object <obj.*ptr_init)( 5 ) ;
cout « "a in obj, after (obj. *ptr_init) ( 5 ) = * « obj.a « endl; / / access through object
pointer (pobj->*ptr_init) ( 5 ) ;
cout « "a in o b j , after (pobj->*ptr_init) ( 5 ) = " « obj.a < < endl;
)
Ad
a in o b j , a f t e r o b j . * i p = 10 is 10
a in ob j, a f t e r pobj->*.ip = 10 is 10 a in o b j ,
a f t e r (obj.*ptr_init)( 5 ) = 5 a in obj, a f t e r
(pobj->*ptr_init)(5) = 5
a
l
;
Copyrighted material
Chapter 1: Object-Oriented Paradigm 27
b
l
;
)
friend int sum( X x ) ;
Run
Sum =
11 Sum
= 15
Copyrighted material
Chapter 1: Object-Oriented Paradigm 27
♦ include <process.h>
void out_of_memory ( )
{
cout « "Memory exhausted, cannot allocate"; e x i t t 1 ) ;
/ / terminate the program
)
void main () (
int *ip;
long total_allocated = OL; / / install error
function set_new_handler( out_of_memory
);
void display! l i s t
"first ) {
l i s t "traverse;
cout << "List traversal yields: " ;
/ / scan f o r a l l the elements
f o r t traverse = f i r s t ; traverse; traverse = traverse->next )
cout < < traverse->data < <
" , " ; cout << endl;
)
void main
(void) {
int choice, d a t a ;
l i s t " f i r s t = NULL; / / i n i t i a l l y points to NULL l i s t "node; / / pointer to
new node to be created while( 1 ) {
cout « "Linked L i s t . . . " « endl;
cout < < " 1 . Insert" << endl;
cout < < " 2 . Display" << endl;
cout << " 3 . Quit" « endl; cout
<< "Enter Choice: " ; c i n >>
.choice-switch (choice) {
case 1:
cout « "Enter
Data: " ; cin »
data;
node = new
l i s t ( data ) ; i f f
f i r s t = = NULL )
first =
node; else
first->insert( node ) ;
b
re
ak
;
ca
se
2:
display! f i r s t ) ;
break; / / Display
l i s t , case 3:
ex
it( 1 )
;
default
:
cout < < "Bad option selected" « endl;
continue;
)
)
Copyrighted material
Chapter 1: Object-Oriented Paradigm 27
Run
Linke
d
List.
. .
1.Inse
rt
2.Disp
lay
3 . Qu
it
Enter Choice: 1
Enter Data: 2
Linked L i s t . . .
1.Insert 2.Display
3.Quit
Enter Choice: 2
L i s t traversal yields: 2 ,
Linked L i s t . . .
1.Insert
2.Display
3-Quit
Enter Choice: I
Enter Data: 2
Linked L i s t . . .
1.Insert 2.Display
3.Quit
Enter Choice: X
Enter Data: 4
Linked L i s t . . .
1.Insert 2 . Display
3.Quit
Enter Choice: 2
List traversal yields: 2 , 3, 4 , Linked
List. . . 1.Insert 2.Display 3.Quit
Enter Choice: 1
The use of a self-referential class is inevitable in the above program, since each node in the slack has a
pointer to another node of its own type, which is its predecessor (in the case of the stack).
Several problems whose solutions are based on the use of data structures like trees, graphs and lists make
extensive use of self-referential class.
Copyrighted material
Chapter 1: Object-Oriented Paradigm 27
class doubly
linked list first
Copyrighted material
Chapt er 12: Dynam i c Obj ect s 429
void dll::FreeAllNodes<)
i
cout << 'Freeing the node with data: ";
// this points to first node, use it to release all the nodes for< dll 'first
= this; first; first = first->next ) delete first;
)
// "Displays the doubly linked list in both forward and reverse order making >'i
use of the series of next and prev pointers, void displayl dll *first )
{
dll 'traverse = first;
if( traverse == NULL)
(
cout « "Nothing to display !" << endl; // along the list, return;
)
els
e {
cout << "Processing with forward -> pointer:
"; // scan for all the elements in forward
direction for( ; traverse->next; traverse =
traverse->next )
cout << ■->■ « traverse-
>data; // display last element
cout << "->" << traverse->data << endl; cout <<
"Processing with backward <- pointer: "; // scan
for all the elements in reverse direction for( ;
traverse->prev; traverse = traverse->prev )
cout << "->" << traverse->data; //
display first element cout << "->" <<
traverse->data << endl;
)
)
dll * InsertNodet dll 'first, int
data ) (
dll 'node;
node = new dll{ data );
if( first == NULL )
first = node;
else
first->insert( node );
return first;
}
void main( void >
(
int choice, data;
Copyrighted material
dll "first = NULL; //' initially points to NULL cout « "Double Linked List
Manipulation..." << endl; while( 1 ) (
cout << "Enter Choice ([1] Insert, (2] Display, [3J Quit): cin >> choice;
switch (choice) {
Chapt er 12: Dynam i c Obj ect s 429
case 1:
cout « "Enter Data: "; cin >>
data;
first = InsertNode( first, data );
break; case 2:
display( first ) ;
break; // Display list, case 3:
first->FreeAllNodes(); // release all nodes exit( 1 ); default:
cout « "Bad option selected" « endl; continue;
)
)
)
Run
Double Linked List Manipulation...
Enter Choice ([1] Insert,' [2] Display, [3] Quit) : I
Enter Data: 2
Enter Choice ((1) Insert, [2J Display, [3] Quit): 2
Processing with forward -> pointer: ->3 Processing with
backward <- pointer: ->3 Enter Choice ([1] Insert, [2]
Display, [3] Quit):! Enter Data: 2
Enter Choice ([1] Insert, [2) Display, [3J Quit): 2.
Processing with forward -> pointer: ->3->7 Processing with
backward <- pointer: *>7->3 Enter Choice ([1] Insert,
[2) Display, [3] Quit): 1 Enter Data: £
Enter Choice ([1] Insert, [2] Display, [31 Quit): 2
Processing with forward -> pointer: ->3->7->5 Processing
with backward <- pointer: ->5->7->3 Enter Choice ([1]
Insert, [2) Display, [3J Quit) : 0. Bad option
selected
Enter Choice ([1] Insert, [21 Display, [3) Quit): 2
Freeing the node with data: ->3->7->5
Besides handling dynamic data structures, the this pointer finds extensive
application in the following contexts:
♦ Member functions returning pointers to their respective objects.
13
Operator Overloading
13.1 Introduction
The operators such as +, +=. >, ». etc., are designed to operate only on standard data types in structured
programming languages such as C. The + operator can be used to perform the addition operation on integer,
floating-point, or mixed data types as indicated in the expression {a+b). In this expression, the data type of the
operands a and b on which the + operator is operating, is not mentioned explicitly. In such cases, the compiler
implicitly selects suitable addition operation (integer, floating-point, double, etc.,) depending on the data type
of operands without any assistance from the programmer. Consider the following statements:
inc a, b, c; float
x, y, 2 ;
c = a + b; // 1: integer addition and assignment
z = x + y; 1/ 2 : floating-point addition and assignment
x = a + b; // 3: integer addition and floating point assignment
The operators = and + behave quite differently in the above statements: the first statement does integer
addition and assigns the result to c, the second performs floating-point addition and assigns the result to 2, and
the last performs integer addition and assigns the result to the floating-point variable x. It indicates that, the +
operator is overloaded implicitly to operate on operands of any standard data type supported by the language.
Unlike C, in C++, such operators can also be overloaded explicitly to operate on operands of user-defined data
types. For instance, the statement
c3 = AddComplext cl, c2 );
performs the addition of operands cl and c2 belonging to the user defined data type and assigns the result to
c3 (which is also operand of the user defined data type). In C++, by overloading the + operator, the above
statement can be changed to an easily readable form:
c3 = cl + c2;
It tries to make the user-defined data types behave in a manner similar (and have the same look and feet) to the
built-in data types, thereby allowing the user to redefine the language itself. Operator overloading, thus allows
to provide additional meaning to operators such as +,*, >=,+=,etc, when they are applied to user defined data
types. It allows the user to program (develop solution to) the problems as perceived in the real world.
The operator overloading feature of C++ is one of the methods of realizing polymorphism. The word
polymorphism is derived from the Greek words poly and morphism (polymorphism = poly + morphism). Here,poly
refers to many or multiple anamorphism refers to actions, i.e., performing many actions with a single operator.
As staled earlier, the + operator performs integer addition if the operands are of integer type and floating point
addition if the operands are of real type.
The concept of operator overloading can also be applied to data conversion. C++ offers automatic
conversion of primitive data types. For example, in the statement x=a+b, the compiler implicitly con verts the
integer result to floating-point representation and then assigns to the float variable x. But the conversion of
user defined data types requires some effort on the part of the programmer. Thus, operator overloading
concepts are applied to the following two principle areas:
•Extending capability of operators to operate on user defined data.
♦ Data conversion.
Operator overloading extends the semantics of an operator without changing its syntax. The grammatical
rules defined by C++ that govern its use such as the number of operands, precedence, and associativity of the
operator remain the same for overloaded operators. Therefore, it should be remembered that the overloaded
operator should not change its original meaning. However, semantics (meaning) can be changed, but it is
advisable to retain the predefined logical meaning.
Copyrighted material
allows almost all operators to be overloaded in which case atleast one operand must be an instance of a class
(object). It allows overloading of the operators listed in Table 1 3.1.
The precedence relation of overloadable operators and their expression syntax remains the same even after
overloading. Even if there is a provision to change the operator precedence or the expression syntax, it does
not offer any advantage. For instance, it is improper to define a unary division (/) or a binary complement (-),
since the change of precedence or syntax leads to ambiguity. For example, defining an operator * * to
represent exponentiation as in the case of Fortran language, appears to be obvious, however, interpretation of
the expression a* *b, leads to confusion; whether to interpret it as a*(*b) or (a) * Mb), because, C++already
interprets itasa*(*b).
Copyrighted material
Operator to be overloaded (see Table 13.1)
r
Arguments to Operator Function
void
main
() {
Index idxl, idx2; / / idxl and idx2 are the objects of Index
cout « "\nlndexl = ■ << idxl.Getlndex( ) ; cout
« "\nlndex2 = 1 « idx2 .Getlndex( ) ,-
idxl = idx2++; / / return object idx2++ is assigned to object idxl
idx2++; / / return object idx2++ is unused
cout « ■Nnlndexl = " « idxl.Getlndex( ) ; cout
<< "\nlndex2 = " « idx2 .GetlndexO ;
)
Run
Ind
exl
= 0
Ind
ex2
= 0
Ind
exl
= 1
Ind
ex2
=2
In the program index3 . cpp, the statements used to return an object are the following: Index temp;
value = value + 1; temp.value = value; return temp; In this program, the statements,
value = value + 1;
return Index( value ) ;
perform the same operation as achieved b; ihe above four statements. It creates a nameless object by
passing an initialization value. To perform this operation, the following parameterized constructor is
added as the constructor member function to the Index class:
Index( int val )
Copyrighted material
(
val"~ - val;
cout << "(" « real;
cout « ", " « imag « ■)■;
}
c m
o p
m ;
p temp.real = real + c2.real; temp.imag = imag +
l c2.imag;
e
return( temp );
x
// object temp of complex class
// add real parts
t
// add imaginary parts
e
// return complex object
)
void
main
() (
complex cl, c2, c3; // cl, c2, c3 are object of complex class cout « "Enter Complex
Number cl .." « endl; cl.getdata();
cout « "Enter Complex Number c2 . . " « endl;
c2.getdata();
c3 = cl. AddComplex ( c2 ); // add cl and c2 and assign the result to c3
c3.outdata ( "c3 = cl .AddComplex ( c2 ): ");
)
Run
Enter Complex Number cl . .
Real Part ? 2^3.
Imag Part ? 2 . 0
Enter Complex Number c2 . .
Real Part ? XJ2.
Imag Part ? 1.5
c3 = cl.AddComplex( c2 ): (5.5, 3.5)
Copyrighted material
temp.x=
temp.y=
temp
5.5
3.5
Copyrighted material
X + c2.x
y + c2.y
return(temp);
c3
2.5 2.0 3.0 1.5
C2;
5.5 3.5 cl
Copyrighted material
Bun
Indexl
= 5
Index2
= 10
Indexl is less than Index2
The concept of overloading the comparison operator < in the above program is similar to
overloading arithmetic operators. The operator function < () returns TRUE or FALSE depending
on the magnitudes of the Index operands.
Strings Comparison
The relational operators such as <, >, ==, etc., can be overloaded to operate on strings.
These operators return TRUE or FALSE depending on the contents of the string arguments. The
program strcmp. cpp illustrates the overloading of relational operators in a string-class*.
cl = cl + c2;
can be replaced by
cl += c2;
The program complex4. cpp illustrates the overloading of arithmetic assignment operators to
manipulate complex numbers.
Copyrighted material
void operator *= { complex c2 )
void operator /= { complex c2 )
);
// addition of complex numbers, cl += c2 instead of cl = cl + c2; void complex;:operator +=
( complex c2 ) {
real = real + c2.real;
imag = imag + c2.imag;
}
// subtraction of complex numbers, cl -= c2, i.e., cl = cl - c2; void complex::operator -= <
complex c2 ) {
real = real - c2.real;
imag = imag - c2.imag;
Copyrighted material
460 Mastering C++
Copyrighted material
Chapter 13: Operator Overloading
Run
Enter Complex Number cl . .
Real Part ? 2^1
Imag Part ? 2.0
Enter Complex Number c2 . .
Real Part ? 3.0
Imag Part ? 1. 5
Entered Complex Numbers are... cl = (2.5,
2) c2 = (3, 1.5)
Computational results are... let c3 = cl, c3 *= c2:
(5.5, 3.5) let c3 * cl, c3 -= c2: (-0.5, 0.5) let c3 = cl,
c3 *= c2: (4.5, 9.75) let c3 = cl, c3 /= c2:
(0.933333, 0.2)
Observe the difference between the operator function + () defined in the program complex3 . cpp and
operator function += () defined in the program complex4 . cpp. In the former, a new temporary object of
complex type must be created and returned by the function, so that the resultant object can be assigned to a
third complex object, as in the statement
c3 = cl + c2;
In the latter, the function operator += () is a member function of the object (destination object's class), which
receives the result of computation. Hence, the function operator +=() has no return value; it returns void
type. Normally, the result of the assignment operation is not required. In a statement, such as,
c3 ♦= c2;
the operator alone is used without bothering about the return value.
The use of the arithmetic assignment operator in a complicated statement such as, c3 = cl += c2;
requires a return value. Such requirements can be satisfied by having the function operator += (), which
terminates with the statement such as
return! *this );*orreturn complex( real, imag ) ,-
In the first case, the current object is returned and in the latter case, a nameless object is created with
initialization and is returned as illustrated in the program complexS. cpp.
// complex5.cpp: Overloading of += operator for complex expressions •include <iostream.h> class complex
private:
float real;
float imag;
public:
complex( ) { / / no argument constructor
real = i imag 0.0;
void getdata() // read complex number
■"
Run
Enter Complex Number cl . .
Real Part ?
Imag Part ? 2.0
Enter Complex Number c2 . .
Real Part ?
Imag Part ? 1.5
On execution of c3 = cl c2
Complex ci: (5.5, 3.5)
Complex c2: (3, 1.5)
Complex c3: (5.5. 3.5)
tor function is called recursively leading to stack overflow. Hence, prefixing of the scope resolution operator
to the new operator forces to use the standard new operator supported by the language instead of the one
defined in the program. The class vector has a data item of type dynamic array, defined by int *array.
Another statement in the above function
my_vector->array = new intFARRAY_SIZE); // calls : :new creates an array and dynamically
allocates memory to it.
Similar to the overloaded new operator function, the overloaded delete operator function handles the
process of releasing memory that has been allocated during the dynamic object creation by the new operator;
it also releases the memory allocated to the internal data-item array through the function call
delete my_vector; It invokes the
overloaded operator function
void operator delete( void* vec ) to release the entire memory resource allocated to the my_vector
object and its data members.
Copyrighted material
Chapter 13: Operator Overloading
operator
BasicTypeO (
/ / steps for converting
/ / Object attributes to BasicType
}
};
class Degree
{
private:
float degree; // Degree
public:
Degree() // constructorO, no arguments
{
degree = 0.0;
)
// degree = radian: Conversion routine at the destination Degree( Radian
rad ) // constructorl, one-argument constructor {
Mastering C++
>;
Chapter 2: Moving from C to C++ 33
Run:
Hello World
The standard C library function printf () sends characters to the standard output device. The Heilo World
program will also work in C++, since it supports the ANSI-C function library. However, the program could
be rewritten using C++ streams. The C++ equivalent of the Hello World program is listed in the program
hello. cpp.
Run:
Hello Wor^d
The header file iostream.h supports streams programming features by including predefined stream
objects. The C++*s stream insertion operator, « sends the message "Hello World" to the predefined console
object, cout.which in turn prints on the console. The Hello World program in C++ is shown in Figure 2.1 for
the purpose of comparative analysis.
{ function begin
The various components of the program hello, cpp.shown in Figure 2.1, are discussed in the following
section:
First Line - Comment Line
The statement which starts with symbols // (i.e., two slash characters one after another without a spa«) is
treated as comment. Hence the compiler ignores the complete line starting from the // character pa ;r.
/ / complex8.cpp: Addition of Complex Numbers with friend feature •include <iostream.h> class
complex C
Copyrighted material
Chapter 13: Operator Overloading
private:
float real;
f
loat
imag;
publi
c:
complex()
()
complex{ int
realpart ) (
real = realpart;
)
void
readd
ataO
(
cout « "Real Part ?
cin » real; cout «
"Imag Part ? "; cin
>> imag;
)
void outdata { char *msg ) // display complex number
{
cout « endl « msg; cout
« ■(■ « real; cout « ",
" « imag « ")";
)
friend complex operator + ( complex cl, complex c2 );
);
// note that friend keyword and scope resolution operator are not used
complex operator + ( complex cl, complex c2 )
(
complex c;
c.real = cl.real +
c2.real; c. imag =
cl.imag + c2.imag;
returnf c ) ;
)
v
o
i
d
m
a
i
n
(
)
{
complex cl, c2, c3 = 3.0;
cout << 'Enter Complexl cl..:" « endl;
cl.readdata{);
cout « "Enter Complex2 c2..:" « endl;
c2.readdata(); c3 » cl + c2;
c3.outdata( "Result of c3 = cl + c2: " ); // 2.0 is
considered as real part of complex c3 = cl + 2.0; // c3
Mastering C++
void
main
() {
complex cl, c2, c3 = 3;
cout « "Enter Complexl cl..:" «
endl; cin » cl;
cout « "Enter Complex2 c2..:" «
endl; cin » c2; c3 - cl + c2;
cout « -Result of c3 = cl + c2:
"; cout « c3;
// 2.0 is considered as real part of
complex c3 = cl + 2.0; // c3 = cl +
complex(2.0)
cout«endl«"Result of c3 ■ cl + 2.0: "; //c3scl + complex(2 .0) ; cout « c3;
// 3.0 is considered as real part of
complex c3 = 3.0 + c2;
cout<< endl«'Result of c3 ■ 3.0 + c2 : "; //c3=complex {3 .0) * c2 ; cout «
c3;
constructor also gets invoked when arguments are passed by value to functions and when values are returned
from functions. When an object is passed by value, the argument on which the function operates is created
using a copy constructor. If an object is passed by its address or reference, the copy constructor of course
would not be invoked, and the copies of the objects are not created. When an object is returned from a
function, the copy constructor is invoked to create a copy of the value returned by the function.
Copyrighted material
Chapter 13: Operator Overloading
outgrows the size of memory in the machine, requiring an undesirable amount of s vapping activity. The first
step in attacking this problem is to find where memory is being requested, used, and not returned.
Approach
In C++, it is easy to overload the built-in new and delete operators with user-supplied versions and thereby
determine when the memory is requested and to which memory location it is bounded. The program
mleak.cpp overloads new and delete operators and records the memory location to which the request is
bound, in the disk file space. raw. It also records all those bindings that are released using explicit memory
free request command.
/ / mleak.cpp: Memory leak tracing • include
<iostream.h> •include <stdio.h> ♦include
<process.h> •include <alloc.h> ♦include
<string.h>
//global information
static space_debug = 1; // space_debug switch, ON
FILE * fp_space = NULL; // file pointer to the debug info
void * operator new( size_t size )
{
void *ptr;
if( space_debug ) (
if( fp_space == NULL ) // first time call to new or delete (
// open leak debug info file which is unopened if( (fp_space = fopen( "space.raw -, "w" )) ==
NULL ) {
cout « "Error opening space.raw in write mode"; exit( 1 ) ;
)
)
The space_debug variable allows the programmer to decide whether to trace a particular portion
of code or not. When tracing is desired it must be set to a nonzero (debug ON) value. When the
following statements:
vector = (int *) new int [ 10 ]; buffer =
(char *) new char( 6 3;
are invoked in the program, the overloaded new operator allocates the requested amount of memory and
returns a pointer to the memory location to which it is bound. In addition, it records this memory address to
which it is bound, in the disk file space. raw. Similarly, the overloaded delete operator releases the memory
pointed to by the input pointer and also records the memory address in the disk file.-In the above Run, the
information recorded in space. raw file is the following:
newt 36 ) -> bd2 newt
516 ) -> bfa newt 36 )
-> e02 newt 516 ) ->
e2a newt 36 ) -> 1032
newt 516 ) -> 105a
newt 10 ) -> 1262
newt 6 ) -> 127a free
<- 1262 free <- bfa
free <- bd2 free <- e2a
free <- e02 free <-
105a .'free <- 1032
The first six requests are made by the program execution start-up routine. They can be discarded in the
memory leak tracing analysis. The seventh and eighth requests are made in the program explicitly. Similarly,
the last six memory free requests made by the system, can be discarded during analysis. These requests vary
from system to system. The first request to free memory is made by the statement
delete vector; // vector is deallocated The pointer
returned for the requests
vector = (int *) new int[ 10 ];
buffer = (char *) new chart 6 1; are the
following
newt 10 ) -> 1262
newt 6 ) -> 127a
By tracing the above allocation address information in the free list, it can be detected that new (6) pointer
address is not released, leading to memory leak. In the program it can be observed that, the memory
allocated for the variable vector is released explicitly whereas, the memory allocated for the variable buffer
is not released. It can also be noticed from the trace of memory debug information.
Operator overloading and data conversion features of C++ provide an opportunity to the user to redefine the
C++ language. Polymorphism feature of C++ is a bonus for the user to customize C++ to their taste. Of
course, it can be misused, since C++ does not restrict the user from misusing (exploiting)
Enter Number 2 : 10.
sum = numl + num2
Run2
Enter Number 1: £ Enter Number 2: 10. sum = numl + num2 ■
-5
is supposed to perform addition of two numbers numl and num2, but instead it performs subtraction. The
statement in the body of the overloaded operator function number operator* (. .)
sum.num = num - num2.num; // instead of addition, subtraction is done performs subtraction
instead of addition. Such neglected use of operator overloading is not taken care by the C++ compiler, but it
is the responsibility of the programmer.
As operator overloading is only a notational convenience, the language should try to prevent its misuse
(but C++ does not prevent). It is indeed said that the meaning of operators applied to standard data types cannot
be redefined. The intent is to make C+ + extensible, but not mutable. Hence, operators cannot be overloaded for
enumerations, although it would be sometimes desirable and fully sensible.
Guidelines
It is essential to follow syntax and semantic rules of the language while extending the power of C++ using
operator overloading. In fact, operator overloading feature opens up a vast vistas of opportunities for creative
programmers (for instance, new and delete can be overloaded to detect memory leaks as illustrated earlier).
The following are some guidelines that needs to be kept in mind whiie overloading any operators to support
user defined data types:
1. Retain Meaning
Overloaded operators must perform operations similar to those defined for primitive/basic data types. The
operator + can be overloaded to perform subtraction; operator * can be overloaded to perform division
operation. However, such definitions should be avoided to retain the intuitive meaning of the operators. For
example, the overloaded operator + () function operating on user-defined data-items must retain a meaning
similar to addition The operator + could perform the union operation on set data type, concatenation on
string data type, etc.
2. Retain Syntax
The syntactic characteristics and operator hierarchy cannot be changed by overloading. Therefore,
overloaded operators must be used in the same way they are used for basic data types. For example, i f cl and
c2 arc the objects of complex class, the arithmetic assignment operator in the statement
Cl + = c2;
sets cl to the sum of cl and c2. The overloaded version of any operator should do something analogous to the
standard definition of the language The above statement should perform an operation similar to the statement
cl = cl * c2;
Copyrighted material
Chapter 14: Inheritance 507
The program union. cpp demonstrates the.mechanism of extending the Bag class by using the feature of inheritance.
In this case, a new class Set is derived from the existing class Bag without any modifications. A derived class Set
inherits all the properties of the class Bag and extends itself by adding some of its own features to support set assignment
and union operation.
Copyrighted material
508 Mastering C++
Copyrighted material
508 Mastering C++
♦ Multilevel Inheritance
♦ Hybrid Inheritance
♦ Multipath Inheritance
The differtnt forms of inheritance relationship is depicted in Figure 14.6. The pictorial representa tion of inheritance
showing the interrelationship among the classes involved is known as the inherit ance tree or class hierarchy. Base
classes are represented at higher levels (top of the hierarchy, say >"oot) and derived classes at the bottom of the
hierarchy. The arrow directed from the derived class towards the base class, indicates that the derived class accesses
features of the base class without modifying it, but not vice versa (Some use convention of representing the arrow in the
opposite direction to indicate inherited from or derived from).
Single Inheritance: Derivation of a class from only one base class is called single inheritance. The sample program,
union.cpp, discussed above falls under this category. Figure 14.6a depicts single inheritance.
Multiple Inheritance: Derivation of a class from several (two or more) base classes is called multiple inheritance. Figure
14.6b depicts multiple inheritance.
Hierarchical Inheritance: Derivation of several classes from a single base class i.e., the traits of one class may be
inherited by more than one class, is called hierarchical inheritance. Figure 14.6c depicts hierarchical inheritance.
B
O{
cout<<"No-argument constructor of the base class B executed first\n"; )
);
class D: public B / / publicly derived class
{
public: DO {
cout«"No-argument constructor of the derived class D executed next"; )
J;
void main{ )
{
D objd; / / access both base constructor
)
Run
No-argument constructor of the base class B executed first No-argument constructor of the derived class D
executed next
Bun
No-argument constructor of the base class B One-argument
constructor of the derived class D
Copyrighted material
522 Mastering C++
void main ( ) (
D objd; / / base constructor
Run
No-argument constructor of a base class B 2 No-argument constructor of
the base class Bl No-argument constructor of the derived class D
The siatemenl
class D: public Bl, virtual B 2 / / public Bl, private virtual B 2
specifies thai Ihe class D is derived from the base classes Bl and B 2 . The statement
DO : B 1 ( ) . B 2 ( )
in the derived class D, specifies that, the base class constructors must be called. However, the con structors are invoked in the order
B2 ( ) , Bl, and D (), instead of the order in which base classes appear in the declaration of the derived class, since, the virtual base
class constructors are invoked first followed by an orderly invocation of constructors of other classes.
Run
No-argument No-argument No- constructor of a base class B constructor of a base class Dl constructor of a derived class D2
argument
Copyrighted material
528 Mastering C + +
void main ()
r
i
B b( 2 , 3 ) ;
b.print();
}
Run
4211
2
The compiler converts the constructor of the class B into the following form;
B( int a, int b ) t
x = <y+b);
y = a;
)
In the above converted constructor, it should be noted that the statement
x = (y+b);
refers to the data membery which is still not initialized. Hence, the program produces the wrong result.
// cons14.cpp: overloaded members in base and derived classes •include <iostream.h> class B // base
class {
protected:
int x;
int y;
public:
B() {)
void read{)
(
cout « "X in class B ? " ; cin » x;
cout « "Y in class B ? ■ ; cin » y;
);
void showO {
cout « "X in class B ■ ■ « x << endl; cout « "Y in
class B = 1 « y << endl;
}
>;
Input Streams
The inpul streams allow to perform read operation with input devices such as keyboard, disk, etc. Input from
the standard stream is performed using the cin object. C++ uses the bit-wise right-shift operator for
performing console input operation. The syntax for standard input streams operation is as follows: cin >>
variable;
The wordcin is followed by the symbol»(extraction operator) and then with the variable, into which the input
data is to be stored. The use of cin in performing an input operation is shown in Figure 2.3.
object cin
—► extraction or get operator
variable of standard or user defined data type
cin » variable;
Variable
Figure 2.3: Input with cin operator
The following are examples of stream input operations:
Copyrighted material
528 Mastering C + +
Derived class
r
base class I
The default visibility mode isprivate. If visibility mode is specified, it must be either public or
private. In multiple inheritance also, the inheritance of base classes with visibility mode publ ic, implies
that the public members 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. Inheritance of base classes
with visibility mode private causes both the public and protected members of the base class to become
private members of the derived class. However, in both the cases private members of the base class are
not inherited and they can be accessed through member functions of the base class.
The following declaration illustrates the concept of multiple inheritance: class D: public Bl, public
B2 / / multiple inheritance {
p-ivate:
Copyrighted material
Chapter 14: Inheritance 152
These situations create ambiguity in deciding which of the base class's function has to be referred. This
problem is resolved using the scope resolution operator as shown in Figure 14.15. The program mul_inh4 . cpp
illustrates the same.
/ / mul.Jnh4.cpp: overloaded functions in base classes ♦include <iostream.h> class A / / base classl
t
char ch; / / private data, default public:
A t char c )
{ ch = c; }
void showt)
{
cout << ch;
)
);
class B // base class2
{
char ch; // private data, default public:
B( char b )
f ch = b; }
void showO
{
cout « ch;
)
);
class C: public A, public B
{
char ch; / / private data, default public:
C ( char cl, char c2, char c3) : A( cl ) , B( c2 ) {
Ch = c3;
} ;
Vehicle
T
Light Motor Heavy Motor
Copyrighted material
Chapter 14: Inheritance 153
I I
Gear Motor Non Gear Motor Passenger Goods
Copyrighted material
Chapter 14: Inheritance 154
class D
student T
Internal Exam ii External Exam
i A
•
Result
Copyrighted material
S60 Mastering C++
Copyrighted material
562 Mastering C + +
class B { class B
};
class D class B
B obj b; B objb;
};
In the case of inheritance (kind of relationship), the constructors of base class are first invoked before the
constructor of the derived class. Whereas, in the case of has-a relationship, the constructor of the class D is
invoked first and then the object of B is created. The concept of creating the member objects first using
respective member constructors and then the other ordinary members can also be accomplished in has-a
relationship by using an initialization-list in the constructor of the nested class. Consider the following class
declarations class B (
/ / body of a class
};
class D {
B ObjectB; / / b is a object of class B
public:
D( arg-list ) : ObjectBt arg-listl );
};
The classes publication and sales have the same declaration as in inheritance relation but they are used in
a different way by the book class. Although containcrship is an alternative to inheritance and offers the
functionality of inheritance, it does not provide flexibility of ownership. Inheritance relationship is simpler to
implement and offers a clearer conceptual framework.
Copyrighted material
562 Mastering C + +
void
displ
ay()
(
cout << "\tTitle = " << title <<
endl; cout << "\tPrice = " «
price « endl;
)
);
class sales //
base class {
private:
float PublishSales[3]; //sales of publication for the last 3 months
public:
void
getdat
a();
void
displa
y{);
void sales::getdata()
{
int i ,-
for( i = 0; i < 3;
i++ J {
cout << "\tEnter Sales of " << i+1 « "
Month: "; cin » PublishSales[i];
)
}
void
sales::display(
) {
int i;
int TotalSales = 0;
for( i = 0; i < 3;
i++ ) (
cout<<"\tSales of " << i+1 «" Month = " « PublishSales[il « endl:
Run
Enter Principle Amount: 1Q0Q Enter
Time (in years): 2 Enter Rate of Interest:
£ Simple Interest = 100 Total Amount =
1100
Copyrighted material
562 Mastering C + +
syntax of defining variables with the constant qualifier is shown in Figure 2.5. Note that if DataType is
ommitled. it is considered as int by default.
v
standard or user defined data type: char, short, int.
float, etc.
numeric constant must be of type DataType as
specified
const [DataType] VariableName = ConstantValue;
Copyrighted material
15
Virtual Functions
15.1 Introduction
Polymorphism in biology means the ability of an organism to assume a variety of forms. In C++, it
indicates the foim of a member function that can be changed at runtime. Such member functions are
called virtual functions and the corresponding class is called polymorphic class. The objects of the
polymorphic class, addressed by pointers, change at runtime and respond differently for the same
message. Such a mechanism requires postponement of binding of a function call to the member
function (declared asvirtual) until runtime.
Polymorphis
m
______________
It has been observed that, function overloading and operator overloading features of C++ have
allowed to realize polymorphism. Yet, there is another mechanism to implement polymorphism in
C++; through dynamic binding. Figure 15.1, illustrates the taxonomy of polymorphism in C++.
Function overloading is realized by invoking a suitable function whose signature matches with the
arguments specified in the function call statement. Operator overloading is realized by allowing
operators to operate on the user defined data-typtc with the same interface as that of the standard
data types. In both cases, the compiler is aware of the complete information regarding the type and
number of operands. Hence, it is possible for the compiler to select a suitable function at the
compile-time.
Copyrighted material
572 Mastering C++
Run
Father name: Eshwarappa
Father name: Eshwarappa
In main(). the statement
Father *fp; / / pointer to the Father class's objects; defines a pointer variable f p. The statement
fp ■ &fl; / / f p points to Father class object assigns the address of the object f 1 of the class Father
to fp. After this, when statement such as
fp->show<); / / display father showt) function is executed, the member function defined in the class Father
is invoked. In C++ base class pointer is fully type-compatible with its derived class pointers and hence, the
statement such as
f p = &sl; / / valid assignment is valid. It assigns the address of the object si of the class Son to fp.
After this, when statement
fp->show(); / / guess what is the output ? Father or Son! is executed, (it is interesting to note that) it still
invokes the member function show ( ) defined in the class Father!
There must be a provision to use the member function show { ) to display the state of objects of both the
Father and Son classes using the same interface. This decision cannot be taken by the compiler, since the
prototype is identical in both the cases.
In C++, a function call can be bound to the actual function either at compile time or at runtime.
Resolving a function call at compile time is known as compile-time or early or static binding whereas, resolving a
function call at runtime is known as runtime or late oxdynamic binding. Runtime polymorphism allows to
postpone the decision of selecting the suitable member functions until runtime. In C++, this is achieved by
using virtual functions.
Virtual functions allow programmers to declare functions in a base class, which can be defined in each
derived class. A pointer to an object of a base class can also point to the objects of its derived classes. In this
case, a member function to be invoked depends on the the class's object to which the pointer is pointing. When
a call to any object is made using the same interface (irrespective of object to which pointer variable is
pointing), the function relevant to that object will be selected at run time. The program parent2 . cpp illustrates
the effect of virtual functions on an overloaded function in a class hierarchy.
Copyrighted material
574 Mastering C++
A derived class pointer may address objects of the derived class, but not objects of the base class
Figure 15.2: A base class pointer may address a derived class object
void
main{ )
{
float
radius;
float
area;
cout < < "Enter Radius of Circle: " ;
cin » radius;
area = PI * radius * radius;
cout << "Area of Circle = " < < area;
)
Run
Enter Radius of Circle: 2
Area of Circle = 12.5808
Copyrighted material
574 Mastering C++
Run
Hello
World
Misuse
The function display ( ) , is supposed to output the input string argument passed to it onto the
console. But accidental use of a statement such as
strcpyt msg, "Misuse" ) ; in display ( ) modifies the input argument. This modification is
also reflected in the calling function; (.;<*e the second message in the output) the string argument is a
pointer type and any modification in function will also be reflected in the calling function. Such
accidental errors can be avoided by defining
Ok
Ok
Base class
Base class data members
X
Not allowed!
Pointer to
derived class
A
Figure 15.4: A base class pointer can address data members inherited by a derived class
Copyrighted material
574 Mastering C++
C++ provides a solution to invoke the exact version of the member function, which has to be decided at
runtime using virtual functions. They are the means by which functions of the base class can be
overridden by the functions of the derived class. The keyword virtual provides a mechanism for defining
the virtual functions. When declaring the base class member functions, the keyword vir-tua 1 is used
with those functions, which are to be bound dynamically. The syntax of defining a virtual function in a
class is shown in Figure 15.5.
class MyClass {
public:
keyword
Virtual functions should be defined in the public section of a class to realize its full potential benefits.
When such a declaration is made, it allows to decide which function to be used at runtime, based on the
type of object, pointed to by the base pointer, rather than the type of the pointer. The program f
amily2 .cpp illustrates the use of base pointer to point to different objects for executing different
implementations of the virtual functions.
{
cout < < "point" < < endl;
)
);
class line: public graphics
{
public:
v
o
i
d
d
r
a
w
(
)
{
cout < < "line" « endl;
)
);
class triangle: public graphics <
public:
void drawt)
{
cout << "triangle" < < endl;
)
);
class rectangle: public graphics {
public:
v
o
i
d
d
r
a
w
Copyrighted material
574 Mastering C++
{
)
(
cout « "rectangle" « endl;
)
);
class c i r c l e : public
graphics {
public:
v
o
i
d
d
r
a
w
f
)
(
cout « "circle" « endl;
>
);
void main ( )
{
graphics
point_obj; line
line_obj;
triangle tri_obj;
rectangle
rect_obj; circle
circle_obj;
graphics
*basep[] = {
&point_obj, &line_obj, &tri_obj,
&rect_obj, &circle_obj
);
cout « 'Following figures are drawn with basep [ i ] - > d r a w { ) . . . " « endl; f o r { int i = 0; i < 5;
i++ ) basep[i]->draw( ) ;
Chapter 15: Virtual Functions 58:-
Run
Following figures are drawn with basep[i]->draw{) . . .
point
line
triangle
rectangle
circle
In main (}, the statement
fort int i = 0; i < 5; i+
+ ) basep[i]->draw();
invokes a different draw {) version based on the object to which the current pointer basep [ i J is
pointing. (See Figure 15.7.)
graphics Parent class
draw()
draw{)
drawn code in parent
child classes
line draw C)
Copyrighted material
574 Mastering C++
rectangle
triangle j circle
draw(}
draw{) draw()
15.9 What are virtual destructors ? How do they differ from normal destructors ? Can constructors
I>e declared as virtual constructors ? Give reasons.
15.10 Explain how dynamic binding is achieved by the C++ compilers. What is the size of the
following classes:
class X
(
int x;
public:
void read( ) ;
);
class Y
{
int a ;
public:
virtual void readO ;
);
class Z
{
int a;
public:
virtual void read{ > ;
virtual void show() ,\
};
15.11 What are the rules that need to be kept in mind in deciding virtual functions ?
15.12 Correct the errors in the following program and include missing components:
class ABC
{
int a;
publie:
);
void main{)
{
ABC.al;
al.readt);
al.showO ;
ABC a2 =
10;
a 2 . showd ;
)
Copyrighted material
574 Mastering C++
15.13 Consider an example of book shop which sells books and video tapes. These two classes arc
inherited from the base class called media. Themedia class has command data members such
as title and publication. The book class has data members for storing number of pages
in a book and the tape class has the playing time in a tape. Each class will have member
functions such as read ( ) and show ( ) . In the base class, these members have to be defined
as virtual functions. Write a program which models the class hierarchy for book shop and
processes objects of these classes using pointers to the base class.
Chapter 2: Moving from C to C++ 45
/ / global.cpp: global variables access through scope resolution operator •include <iostream.h> int num
= 2 0 ; void mainO
Bun
Local = 1 0
Global = 20
Global+Local =
30
The program loop. cpp illustrates the accessing of local and global variables within a f o r loop. It
also shows mixing of the single-line comment statement within a single executable statement.
// (OOp.cpp: local and global variables in a loop
♦ include <iostream.h> int
counter = 50; int main ( ) global variable
{ register int // local variable this refers to the
counter; local variable
for(counter
= 1;
counter < 10;
counter**}
Run
50
25
16
12
10
8
7
6
5
Copyrighted material
574 Mastering C++
m
a
i
n
{
)
{
char chl, ch2;
cout « "Enter two Characters <chl,
ch2>: " ; cin >> chl >> ch2;
swapt chl, ch2 ) ; / / compiler invokes swapt char &a, char &b ) ; cout « "On
swapping <chl, ch2>: 1 « chl « 1 " « ch2 « endl; int a, b;
cout « "Enter two integers
<a, b>: cin » a >> b;
swapt a, b ) ; / / compiler invokes swapt int &a, int &b ) ; cout « "On
swapping <a, b>: ■ « a « ■ " « b « endl; float c , d;
cout « "Enter two floats <c, d>: ■;
cin » c » d;
swapt c, d ) ; / / compiler invokes swapt float &a, float &b ) ; cout << "On
swapping <c, d>: 1 << c << ■ 1 << d;
}
Run
Enter two Characters <chl, ch2>: E K
On swapping <chl, ch2>: K R
Enter two integers <a, b>: 5 10
On swapping <a, b>: 10 5
Enter two floats <c, d>: 20.5 99.5
On swapping <c, d>: 99.5 20.5
The above program has three
swap functions void swapt
char & x, char & y ) ;
void swapt int & x, int & y
) ; void swapt float & x,
float & y ) ;
whose logic of swapping is same and differs only in terms of data-type. Such functions
can be declared as a single function template without redefining them for each and
every data type. The C++ template feature enables substitution of a single piece of code
for all these overloaded functions with a single template function as follows: template
<class T>
void swapt T & x , T fit y ) // by reference
{
T t; / / template type temporary variable used in swapping
/ / max with integer data types int
a , b, c ;
cout < < "Enter two integers < a , b > ; " ; cin
>> a > > b; c = max( a, b ) ;
cout < < "max( a , b ) : " << c << endl; / /
max w i t h string data types char
strl[20], str2[20J;
cout << "Enter two strings < s t r l , s t r 2 > : " ; cin
» strl » s t r 2 ;
cout « "max! s t r l , str2 ) : " « max{ s t r l , str2 ) ;
)
Run
Enter two characters <chl, ch2>: A. £
max( chl, ch2 ) : Z Enter two integers
< a , b > : ii £ max{ a , b ) : 6
Enter two strings < s t r l , s t r 2 > : Teiaswi Raikumar max(
s t r l , s t r 2 ) : Tejaswi
In main (J, the statement
cout « "max( s t r l , str2 ) : ■ « maxl s t r l , str2 ) ; has the expression,
max( strl, str2 )
Copyrighted material
574 Mastering C++
The compiler selects the user-defined normal function instead of creating a new function, since the
function call is matching with the user-defined function.
swapped = true;
Enter the elements of the float vector...
Sorted Vector: 3 . 2
8.5 8.9
In main ( ) , when the compiler encounters the statement y/
BubbleSort ( IntNums, size ) ; it creates the bubble sort function internally for sorting
integer numbers; the parameter IntNums is of type integer. Similarly, when the compiler
encounters the statement
BubbleSort( FloatNums, size ) ; it creates bubble sort function internally for sorting floating
point numbers. The same template function can be used to sort any other data types. Note that
the compiler creates a function internally for a particular data type only once and if there are
more requests with the same data type, the compiler accesses the old internally created function.
Usage of Template Arguments
Every template-argument specified in the template-argument-list must be used as a generic data
type for the definition of the formal parameters. If any of the generic data type is not used in the
definition of formal parameters, such function templates are treated as invalid templates. The
use of partial number of generic data types in a function defining formal parameters is also
treated as an error. All the formal parameters need not be of generic type. The following sections
show some function templates which are invalid declarations:
1. No-argument template function
template < class T >
T popt void ) / / error: T is not used as an argument
{
return *--Stack;
)
2. Template-type argument unused
template < class T >
void test ( int x ) / / error: T is not used as an argument {
T temp;
/ / . . test stuff
}
3. Usage of Partial number of template arguments
template< class T, class U >
void insert ( T & x ) / / error: U is not used in the argument
-{
U lPtr;
/ / . . test stuff
)
The template argument U is not used in argument types, and hence, the compiler reports an
error.
S2.y = b;
)
void main( void ) {
A SI; B
S2;
Assign_A{ 3, 4, SI ) ;
Copyrighted material
574 Mastering C++
/ / student.cpp: student record and template with user defined data types •include
<iostream.h> struct stuRec
{
cha
r
n
a
m
e
[
3
0
J
;
i
n
t
a
g
e
;
char collegeCode;
);
template
<class
Copyrighted material
574 Mastering C++
T> void
Display(
T& t ) {
cout « t « endl;
Run
Enter student record details...
Name: Chinamma
Age : JJL
College Code: h
The student record:
Name: Chinamma
Age : 18
public:
DbleStackO ;
void Push( const double & element ) ; double
Pop( void ) ;
unsigned int GetSize( void ) const;
);
As seen in the above three declarations, a separate stack class is required for each and every
data type. Template declaration enables substitution of code for all the three declarations of
stacks with a single template class as follows:
template < class T >
class DataStack
{
T array[25); / / declare a stack of 25 elements of data type T
unsigned int top;
public:
DataStack( ) ;
void Pusht const T & element ) ; T
Pop( void ) ;
unsigned int GetSizet void ) const;
);
The syntax of declaring class templates and defining objects using the same is shown in Figure
16.2. The definition of a class template implies defining template data and member functions.
Copyrighted material
574 Mastering C++
The prefix template <class T> specifics that a template is being declared, and that a type-name T
will be used in the declaration. In other words, DataStack is a parameterized class with T as its
generic data type.
Any call to the template functions and classes, needs to be associated with a data type or a
class. The compiler then instantiates a copy of the template function or template class for the
data type specified. The syntax for creating objects using the class templates is shown in Figure
16.3.
A statement to create an object of type stack that can hold integers is as follows: DataStack
<int> stack_int; / / stack of integers
datatype to be
substituted for template
datatype
Similarly, objects those hold characters, floats, and doubles can be created by the following statements:
DataStack <char> stack_char; DataStack <float> / / stack of characters / / stack of
stack_float; floats
DataStack <double> stack_double; / / stack of doubles However, the usage of these stack
objects is similar to those of normal objects. For instance, to push the integer value 10 into the
stack_int object, the following statement is used:
stack_int.push( 10 ) ;
Template Arguments
A template can have character strings, function names, and constant expressions in addition to tem plate
type arguments. Consider the following class template to illustrate, how the compiler handles the
creation of objects using class templates:
template <class T, int size>
class myclass
{
T arr[size];
);
The value supplied for a non template type argument must be a constant expression; its value must be
known at compile time. When the objects of the class template are created using a statement such as
myclass <float,10> newl; the compiler
creates the following class: class
myclass {
f l o a t arr[10] ;
);
Again if a statement such as,
myclass < i n t , 5> new2; is encountered for creating the object new2, the compiler creates the
following class:
class myclass
{
int arr[ 5 ] ;
);
Copyrighted material
574 Mastering C++
void main( )
int i;
vector <int> int_vect( 5 ) ; vector
<float> float_vect( 4 ) ; f o r ( i = 0; i
< 5; i + + )
int_vect.elem( i ) = i + 1 ; f o r ( i
= 0; i < 4; i + + )
f loat_veot.elem( i } = floatt i + 1 . 5 ) ; cout «
"Integer Vector: "; int_vect.show( ) ;
cout << endl « "Floating Vector: ";
f loat_vect.s h o w ( ) ;
J
Run
Integer Vector: 1 , 2 , 3 , 4 , 5 , Floating
Vector: 1 . 5 , 2 . 5 , 3 . 5 , 4 . 5 ,
Note that the class template specification is very much similar to the ordinary class
specification except for the prefix,
template <class T>
and the use of T in the place of data-type. This prefix informs the compiler that the class
declaration following it is a template and uses T as a type name in the declaration. The type T
may be substituted by any data type including the user defined types. In main { ) , the statement,
vector <int> int_vect{ 5 ) ;
vector <float> float_vect( 4 ) ; creates the vector objects int_vect and f loat_vect to hold
vectors of type integer and floating point respectively. Once objects of class template are created,
the use of those objects is the same as the non-template class objects.
Class Template with Multiple Arguments
The template class is instantiated by specifying predefined data type or user defined data classes.
The data type is specified in angular braces <>. The syntax for instantiating class template is as
follows: TemplateClassName < type > instance;
TemplateClassName < typel, type2 > instance( arguments ) ; The instantiation specifies
the objects of specified data type. If a different data type is to be specified, a new declaration
statement must be used.
The declaration of template classes with multiple arguments is similar to the function
template with multiple arguments. However, the arguments need not be of template type. These
may include character strings, addresses of objects and functions with external linkage, static
class members, and constant expressions. Consider the following declaration:
The member functions defined w i t h its class body have the same syntax as members of non-template-
typc classes. However, member function defined outside the body of a class, for instance, has the
following specification:
template <ciass T>
void
Veccor<7>::read(;
{
body of the read( I
)
Note that, the member functions of a class-template arc treated as function-template type members. The
class Vector can be instantiated as follows: Vector < i n t > vl;
In this case, the i n t specified in angular bracket is first assigned to generic data lypc in the Vector
class and then the same is also passed to its base class.
A derived class of a template based base class is not necessarily template derived class. That is. the non-
tcmplate-bascd derived classes can also be created from the template-based base classes. In this case,
the undefined template argument T has to be specified during derivation, for instance, as follows: class
Vector : public sVector< i n t >
{
>;
It creates a new class called Vector from the template-based base class sVector. The i n t is passed as
template argument type to the base class.
The program union. cpp illustrates the mechanism of extending the class template Bag by using the
feature of inheritance. In this case, a new class template S e t is derived from the existing class template
Bag without any modifications. A derived class template Set inherits all the properties of the class
template Bag and extends itself by adding some more features of its own to support set assignment and
union operation.
Copyrighted material
574 Mastering C++
Copyrighted material
Chapter 16; Generic Programming with Templates 174
Copyrighted material
622 Mastering C++
Copyrighted material
622 Mastering C++
Copyrighted material
626 Mastering C++
17
Streams Computation with Console
In general, there are several kinds of streams to form physical entities such as streams of water (rivers),
streams of electrons (electricity), streams of cars (traffic), and streams of characters (message packet). The
notion of streams and streams Computation can be visualized through the illustration of a river. It may be
the Amazon river flowing into the Atlantic ocean as shown in Figure 17.1. Drops of water collectively
form a continuous stream. Streams join to form a river. Looking over the upper river area to the lower
river area, streams converge into one stream so that a tree of streams is formed, whose root stream goes
into the ocean. One drop from one branch stream may reach the ocean a slightly earlier or later than
another in a different branch stream.
Copyrighted material
626 Mastering C++
Copyrighted material
630 Mastering C++
C++ streams deal with a sequence of characters and hence, ocean in the above figure can be visualized
as an object or a receiver and each drop of water as a character, flowing into the object.
Streams are classified i n t o input streams and output streams. Streams resemble the producer and
consumer model. The producer produces items to be consumed by the consumer. The producers and
consumers are connected by the C++ operators >> or < < . In C++, the I/O system is designed to operate
on a wide variety of devices including console, disks, printer etc. It is designed to provide a consistent and
device independent interface. I t allows uniform use of any I/O device—be it a disk, a terminal, or a
printer as shown in Figure 17.2a. The computer resources involved in the stream computation include
display, keyboard, files, printer, etc. The stream is an object flowing from one place to another. For
instance, in nature, a stream normally refers to the flow of water from the hills to the oceans. Similarly, in
C++, a stream is used to refer to the flow of data from a particular device to the program's variables. The
device here refers to files, memory arrays, keyboard, console, and so on. In C++, these streams arc treated
as objects to support consistent access interface.
MONITOR
PRIMER
DISK
INPUT STREAM
INSERTION
/ OUTPUT STREAM
INTO OUTPUT
Output STREAM
device
Some of the above devices exhibit the characteristics of either a producer or a consumer and others
exhibit the characteristics of both the producer and consumer depending on the operations performed on
them. For instance, the keyboard exhibits the nature of only a producer; printer or monitor screen
Chapter 2: Moving from C to C++ 49
Run
n = 100 m = 100 *p = 100 n = 100 m
= 100 *p = 200
In main (J. the statement
p = &k; / / pointer value changed changes the pointer value of p, but does not effect the
reference variable m and the variable n.
Copyrighted material
whereas, in C, it is optional. The program max. cpp for computing the maximum of two numbers
illustrates the need for the function prototype.
/ / max.cpp: maximum o f two numbers #include
<iostream.h> int main ( )
{
int x, y;
cout « "Enter two integers: ' ; cin » x » y;
cout « "Maximum = " « maxt x , y ) ; / / Error max.cpp 1 1 : . . . return 0 ;
)
i n t max( int a , i n t b ) {
if{ a > b )
return a ; else
return b;
)
Compilation of the above program produces the following errors: Error max.cpp 11: Function 'max*
should have a prototype in f u n c t i o n m a i n O C++ checks all the parameters passed to a function
against its prototype declaration during compilation. It produces errors if there is a mismatch in argument
types and this can be overcome by placing the prototype of the function max ( ) before it is invoked. The
modified program of max. cpp is listed in newmax. cpp, which is compiled without any errors.
char test[40] ; cout << "Enter string:
"; cin.getlinef test, 40 ); cout «
"Output string: ";
cout << test;
)
Run
Enter string: Hello World Output
string: Hello World
In main t). the statement
cin.getline( test, 40 ); reads a string until it encounters the new line character or maximum
number of characters (40). Now, an input of "Hello World" will produce the output as desired. The
istream: :getline member function has the following versions:
istream& getline{signed char*, int len, char = '\n*);
istreamfc getlinetunsigned char*, int len, char = '\n'); They operate in the following ways:
♦ extracts character up to the delimiter
♦ stores the characters in the buffer
♦ removes the delimiter from the input stream
♦ does not place the delimiter into the buffer
♦ maximum number of characters extracted is len-1
The terminator character can be any character. The terminator character is read but not saved into a buffer;
instead, it is replaced by the null character.
The prototype of write () functions is:
ostream: : write ( char * buffer, int size ); It displays size (second parameter) number of
characters from the input buffer. The display does not stop even when the NULL character is
encountered; If the length of the buffer is less than the indicated size, it displays beyond the bounds of
buffer. Therefore, it is the responsibility of the user to make sure that the size does not exceed the length
of the string. The program stand. cpp illustrates the use of write in string processing.
/ / stand.cpp: display stand of "Object Computing with C++"; #include <iostream.h> tinclude <string.h>
void main()
Copyrighted material
C
h
a
p
t
e
r
1
7
:
S
t
e
a
m
s
C
o
m
p
u
t
a
t
i
o
n
w
i
t
h
C
o
n
s
o
l
e
>
fori i = lenl; i > 0; i-- ) (
cout.writet stringl, i ) ; cout << endl;
)
/ / print both the string cout.writet
stringl, lenl ) ; cout.write( string2,
len2 ) ; cout << endl;
/ / above two write( ) can be replaced below single statement cout.writet stringl,
lenl ) . write( string2, len2 ) ; cout << endl; cout.writet stringl, 6 ) ;
)
Run
o
Ob
Obj
Obje
Objec
Object
Object-
Object-C
Object-Co
Object-Com
Object-Comp
Obj ec t-Compu
Object-Comput
Object-Computi
Object-Computin
Ob j ec t-Comput i ng
Object-Computin
Object-Computi
Object-Comput
Obj ec t-Compu
Object-Comp
Object-Com
Object-Co
Object-C
Object-
Object
Obj ec
Obje
Obj
Ob
O
Object-Computing with C++
Object-Computing with C++
Object
Chapter 17: Steams Computation with Console 643
Run
How many students ? 2 Enter Student 1
details.. Enter Name: Teiaswi Enter Marks
Secured: 450 Enter Student 2 details.. Enter
Name: Raikumar Enter Marks Secured: 5 2 1
Enter Student 3 details.. Enter Name: Bindu
Enter Marks Secured: 429 Student Report...
R# Student Marks Percentage
1 Tejaswi 450 75
2 Rajkumax- 525 87
3 Bindu 429 71
Setting Precision
The funciion precision ( ) is a member of the ios class and is used to specify the number of digits to be
displayed after the decimal point while printing a floating-point number. By default, the precision size is
six. This function must be accessed using objects of the ios class (commonly accessed using cout object). It
has the following two forms:
int precisionO; / / returns current precision
int precision(int d ) ;
where d is the number of digits to the right of the decimal point. It sets the floating-point precision and
returns the previous setting. For example, the statements
cout.precision( 2 ) ; cout «
2 . 2 3 « endl; cout « 5 . 1 6 9 < <
endl; cout << 3 . 5 0 5 5 < <
endl; cout « 4 . 0 0 3 « endl;
will produce the following output:
2.23 5.17 3.51 (perfect f i t )
4 (rounded)
(rounded)
(no trailing zeros, truncated)
After displaying an item, the user defined precision will not revert to the default value. Different values
can be processed with different precision by having multiple precision statements. For instance,
cout.precision( 1 ) ; cout « 2 . 2 3 < < endl; cout.precision( 3 ) ;
cout « 5 . 1 6 9 1 « endl;
will produce the following output:
2.2 (truncated)
5.169 (truncated)
Consider the statements:
cout.precision( 3 ) ;
/ / salary.cpp: f i l l i n g and padding
#include <iostream.h> void mainO {
char *desig[5J = { "CEO", "Manager", "Receptionist", "Clerk", "Peon" ) ;
int salary[5J = { 10200, 5 2 0 0 , 2950, 950, 750 } ;
cout << "Salary Structure Based on Designation" « endl;
cout << "---------------------------------------------------------------" « endl;
cout-width( 15 } ;
cout « "Designation";
cout « " " ,-
cout.width( 15 ) ;
cout < < "Salary ( i n R s . ) " << endl;
cout < < "--------------------------------------------------------------" << endl;
for( int i = 0; i < 5; i + + ) {
cout.f i l l ( ' . ' ) ;
cout.width( 1 5 ) ;
cout < < d e s i g f i ] ;
cout < < '
cout.f i l l ( ' * ' ) ;
cout.width(15) ,-
cout < < salary[ i ] < < endl;
}
cout « "-----------------------------------------------------------------■ « endl;
)
Run
Salary Structure Based on Designation
Designation Salary ( i n Rs. )
Copyrighted material
Chapter 17: Steams Computation with Console 643
CPA mnn
.................Manager .........«*5200
...Receptionist
.....................Clerk
.......................Peon
Note that such a form of output representation is extensively used by financial institutions to represent
money transactions so that no one can modify the amount (money representation) easily.
The statements
cout.setf{ ios: : internal, ios:-.adjustf ield ) ; cout.fill ( 1 *' );
cout.precision! 3 )■
cin » hex >> num; // Input in hexadecimal //
output i in decimal,in a field of width 6 cout << "The
input number in decimal = "; cout « setwl 6 ) « num;
}
Run
Enter any nexadecimal number:
The incut number in decimal = 171
The manipulator hex sets the conversion base for cin to 16. So cin interprets the input characters
as digits of a hexadecimal number. The manipulator setw sets the field width as 6 for cout. Thus, the
input to the above program (ab) is converted into decimal and displayed (16*a+b = 16* 10+11 =
171).
Copyrighted material
Chapter 17: Steams Computation with Console 643
The C++ iostream package contains a rather small handful of predefined producer consumer
manipulators, the only instance of consumer being the white-space eater, for example, ws. Other pre-
defined manipulators set stream state variables which influence processing of input and output, for
example, hex. The implementation of the ios class as well as the implementation of the insertion and
extraction operators correspond to the data type of an item they process. The list of non-
parameterized manipulators and parameterized manipulator functions are shown in Table 17.4 and
17.5 respectively. Each one of these can be used with cither thc<< or the >> operator without
incurring any compilc-time errors. But some of them affect only output streams such as cout. and
some others, only input streams such as cin. Unless otherwise mentioned, these manipulators
affect both types of streams. The first six manipulators - dec,hex, oct, ws,endl, and ends are defined
in iostream.h itself and the rest are in the header file iomanip.h.
Copyrighted material
652 Mastering C++
sotf ill (int f char): Sets the fill character to that specified in f char. The fill character is used
to fill (or pad) the empty space in the output field when the width of the output variable is less than
the width of the output field. The default fill character is the space character.
setease (int base): Sets the conversion base according to the integer base, which can assume any
one of the following four values:
0: Base 10 is used for output;
8: Use octal for input and output.
10: Use decimal for input and output.
16: Use hexadecimal for input and output.
The base to be used for input is specified as a part of the input itself - inputs beginning with 0 are
treated as octal, those beginning with Ox arc treated as hexadecimal. Otherwise, the base is
assumed as decimal.
setiosf lags (long flags): The parameter flags can be any of the flags listed in ios stream
class. More than one flag can be set with the same manipulator by ORing the flags.
The statement
cout << setw( 8 ) << 1234; prints the value 1234 right-justified in the field width of 8
characters. The output can be left justified using the statement,
cout << setw{ 8 ) << setiosflags{ ios::left ) « 1234;
The key difference between manipulators and the ios class interface functions is in their
implementation. The ios member functions are used to read the previous format-state, which can be
used to know the current state or save for future usage, whereas, the manipulators do not return the
previous format state. The program f output. cpp illustrates the use of some of the manipulators with
output streams.
/ / foutput.cpp: various formatting flags with the « operator
•include <iostream.h>
•include <iomanip.h>
void main( )
(
int x = 100;
cout << hex << x << ' ' « dec << x << endl;
float f = 122.3434;
cout « f « endl;
cout « setprecision( 3 ) ;
cout << f << endl;
cout << setw( 6 ) « setf ill { ' 0 ' ) ; cout <<
setiosflags{ios: : internal | ios: : showcase); cout « hex « x « endl;
cout « setiosf lags { ios: : scientific ) « f « endl;
)
Run
C i 100
x22.343399
122.343
0x0064
1.223e+02
Copyrighted material
656 Mastering C++
Run
1 2 3 4
Copyrighted material
Chapter^: Moving from C to C+ 51
+
The
above
errors are
produced
due to the
following
statement
in main ()
s
w
a
p
(
&
c
,
&
d
)
;
/
/
C
o
m
p
i
l
a
t
i
o
n
E
r
r
o
r
s
Because
the
expressio
ns &c
and &d
passed to
swap ()
are not
pointers
to integer
data type.
When a
call to a
function
is made,
the C++
compiler
checks its
parameter
s against
the
parameter
types
declared
in the
function
prototype
. The
compiler
Copyrighted material
flags errors if improper -
arguments are passed.
*
q
2.10 Parameters ;
Passing by Reference *
A function in C++ can take q
arguments passed by value, by
pointer, or by reference. The =
arguments passed by reference is t
an enhancement over C. A copy ;
of the actual parameters in the )
function call is assigned to the A call to
formal parameters in the case of t
pass-by-value, whereas the
h
address of the actual parameters
is passed in the case of pass-by- e
pointer. In the case of pass-by-
reference, an alias (reference) of f
the actual parameters is passed. u
Mechanism of parameter linkage n
is shown in Figure 2.8. c
t
Storage Location
Variable Data Type i
Name o Value
Actual —
> Type n
parameter
s
Formal —
> Type w
Value
parameter
a
(a) p
Call-
by- {
value
)
Valu
Formal
parameter
= «
* "
p E
; n
* t
p e
r
Copyrighted material
;
I
t c
e i
m n
N >
a >
m
e c
: o
s
" t
; 2
;
c -
i c
n o
. u
i t
g
n <
o <
r
e "
( I
) t
; e
m
c
i C
n o
. s
g t
e
t S
l t
i a
n t
e i
t s
t
i i
t c
e s
m .
2 .
, .
"
2
5 <
<
)
; e
n
c d
o l
u ;
t
c
< o
< u
t
"
C <
o <
s
t "
I
o t
f e
m
I
t N
e a
m m
: e
:
*
Copyrighted material
"
"
<
< <
<
i
t i
e t
m e
l m
2
<
< <
<
e
n e
d n
l d
; l
;
c
o c
u o
t u
t
«
«
"
C "
o C
s o
t s
: t
:
■
"
«
«
r
u d
p o
e l
e l
a
« r
c «
o
s c
t o
l s
t
« 2
e «
n
d e
l n
; d
l
c ;
o )
u
t Run
Item
< Sales in
< India..
.
" Enter
I Item
t Name:
e PARAM
m Superco
mputer
N Cost o f
a Item:
m 55000
e
:
Copyrighted material
Item Sales in US. . . i
Enter Item Name: CRAY p
Supercomputer _
Cost of Item: 40500 i
Item Cost S t a t i s t i c s . . .
n
Item Name: PARAM
Supercomputer t
Cost: R s . 55000
Item Name: CRAY {
Supercomputer private:
Cost: US$ 4 0 5 0 0 ost
rea
Standard Manipulators mfi
Implementation c
(*f
The previous example was )
easy, since the manipulator did ( os
not accept any parameters in trea
the output statement. The m&
function that overloads the < < ,
operator to accept int
manipulators merely needs to );
call the manipulator with the //
output stream object (cout in Poi
this case). Manipulators nte
accepting parameters initiates r to
many actions. Consider the the
manipulator declared in act
ual
iomanip. h header file, setw
ma
(int) , to illustrate the
nip
implementation of
ulat
manipulators. The declaration or
of this manipulator is: int
ostream & w; /
setw( ostreamfc, int ) ; But in /
Wi
the output statement, setw is
dth
called with only one integer to
argument: be
cout << s e t w { 6 ) << set
i ; Another function (also p
called setw) is needed that u
accepts only one argument of b
type integer. It does not know l
i
which output object needs to
c
have its field-width set. :
Assuming the output object as
cout will unduly restrict its use /
(For instance, i t would not be /
possible to use it directly with C
files). To resolve this impasse, o
the following solution is used. n
s
A class called omanip_int is
t
declared. It has two private r
members; a pointer to function u
(the actual manipulator) and c
an integer that specifies the t
width. It has a constructor that o
sets these members, and a r
friend function that overloads
the « operator and calls the o
m
actual manipulator.
a
c n
l i
a p
s _
s i
n
t
o
(
m
a o
n s
Copyrighted material
t C
r o
e s
a .
m w
& i
d
( t
h
*
(
t
f w
)
)
( ;
o
s r
t e
r t
e u
a r
m n
f
c o
, s
i ;
n )
t // This is
) called
first from
, the
output
i statement
n .
t //It
accepts
t an integer
w and
returns an
) instance
of class
(
omanip_i
nt
f
omanip_i
= nt
setw( int
t w)
f {
; return
omanip_i
w nt( setw,
w ); //
= returns
nameless
t object
w )
;
}
Now
, the
// overloading stream
state
output operator
ment
friend ostream& operator
<< (ostreamfc os, c
omanip_int o) ( out «
return o.f( os, o.w >; setw( 6 )
« i; will
manipulator. first call
) the
); second
Two more functions are now setw
required; one that actually manipulat
manipulates the stream, and or that
another that is invoked from the remember
output statement. They are s the
declared as follows: width
//Actual manipulator passed in
ostreamfr setw( ostream& os, an
int w )
Copyrighted material
instance of the class omanip_int. •
The actual function to be called i
n
is also recorded here. This
c
instance is returned. The first << l
above now has the return value u
of setw (6) - an instance of d
omanip_int on the right, and e
cout on the left. The overloaded
<
function (defined in the class
i
omanipjnt) is invoked, which in o
turn calls the actual manipulator. s
The same concept can be utilized t
while implementing the user- r
defined manipulators. e
a
m
Parameterized Custom .
Manipulators h
Most manipulators do not accept >
parameters and are simple to
use. Sometimes it is necessary to •
pass data to the manipulators, i
n
however, as with the built-in
c
manipulator setw (int). The l
program presented in pmani. u
cpp, implements a manipulator d
that accepts three arguments - e
width, precision, and fill
character. The manipulator is <
useful as a shorthand notation i
for setting the above parameters o
m
to output floating point variables
a
with different width, precision, n
and fill characters. i
p
/ .
/ h
>
p // output
m manipulat
a or taking
n argument
l s of type
. int, int,
c char
p
p c
: l
a
P s
a
s
r
a
m m
e y
t _
e
r
m
i a
z n
e i
d p
M u
a l
n a
i t
p o
u
l r
a
t {
o priv
r ate:
Copyrighted material
int width, precision; i
c n
h t
a |
r i
o
f s
i :
l :
l r
; i
g
p h
u t
b )
l ;
i
c r
: e
//Constructor t
my_manipulator(int tw, u
int tp, char r
tf) : width(tw),precisio n
n(tp),fill(tf) { )
//Overloaded « o
operator s
friend ostream & ;
operator « ( ostreamfc }
os, my_manipulator /
object ) ; /
}; F
//Actual manipulator called u
by overloaded operator « n
friend function c
ostream & operator « t
( ostreamfc os, i
my_manipulator object ) o
{ n
os « setw( object.width )
<< c
setprecision{ object.prec a
ision ) \ « l
setfill{ object.fill ) ;
l
o
s e
d
<
< f
i
s r
e s
t t
i
o
s f
f r
l o
a m
g
s t
( h
i e
o
s
: o
: u
s t
h p
o u
w t
p
o
Copyrighted material
s i
t d
a
t m
e a
m i
e n
n t
t
)
m
{
y
float
_ fl=1
m 23.2
a 734,
n f2=2
i 3.27
p 1,
u f3=1
l 6.16
73;
a
//
t set_f
o loat
r acce
pts
s thre
e e
t para
_ mete
rs-
f
widt
l h,
o prec
a ision
t and
( fill
char
i acte
n r
cout
t
«
set_f
w loat(
, 10,
3,
i * *'
n ) «
t fl «
endl
;
p
cout
, «
set_f
c loat(
h 9 , 2,
,Al
a )«
r f2 «
endl
f ;
cout
«
} set_f
loat(
( 8 , 3,
return my_manipulator ( *#'
w, p, f ) »• / / nameless ) «
object is returned f3 «
) endl
v ;
)
o
Copyrighted material
Run l
***123.273 l
##16.167
t
In main ( ) , the
o
statement
c
t
o
h
u
e
t
n
«
o
r
s
m
e
a
t
l
_
f
f
l
u
o
n
a
c
t
t
(
i
o
1
n
0
,
a
s
3
,
,
s
et_float(
'
10, 3,
*
■•■ )
'
which
)
in turn
<
creates
<
the
nameles
f
s object
l
of the
classmy
<
_manip
<
ulator
(and
e
initializ
n
es its
d
member
l
s) and
;
returns
the
h
same.
a
Thus,
s
the
above
t
output
h
e
c
a
Copyrighted material
statement effectively r
becomes,
cout << e
n
my_manipulator( set_float,
d
10, 3 , ' * ' ) « f l « endl;
l
The class my_manipulator :
is a friend of the overloaded
operator function and c
hence, the mutated output o
statement invokes the u
function, t
friend ostreamfc
<
operator «
<
( ostream& os,
my_manipulator e
object ) n
Necessity of Friend d
Functions l
The function overloading the ;
operators >> and « need not in the
always be declared as friend. If previous
the data members x and y were examples
public members of the class , to insert
POINT, or, if a public member a'newline
function existed in POINT . The
which output the values of x and manipulat
y, the friend function
or endl is
declarations would be
the
unnecessary inside the class.
function
that is
How do the manipulators
declared
work with the «
as,
operator? o
Cons stream
i far &
d endl
e (ostream
r far &) ;
in the
t header
h file,
iostream.
e
h. Thus,
endl, is a
u function
s that
a accepts a
g reference
e to an
ostream
o (such as
f cout) and
returns
the same
t
(a
h reference
e to an
ostream).
m Recall
a that
n invocatio
i n of a
p function
u with its
name
l
without
a any
t parenthes
o es is
Copyrighted material
considered as a pointer to a
function. Now it is simple to
understand the appearance of the
endl on the right side of the <<
operator; the operator is
overloaded to have pointers to
functions of this type (that
accept a reference to an ostream
and returns the same).
Review Questions
17.1 What are streams ?
Explain the features of C++
stream I/O with C's I/O system.
17.2 List C++ predefined
streams and explain them with
suitable example programs.
17.3 Draw console stream
class hierarchy and explain its
members.
17.4 What is the difference
between the statements ?
cin » ch;
ch = cin.get();
17.5 Write a program to
illustrate the difference between
cin and get line while reading
strings.
17.6 What is the output of the
following statements:
(a) cout « 65;
(b) cout.put( 65 ) ;
(c) cout.putt 1A' ) ;
17.7 Write a program to print
the ASCII table using streams.
17.8 Write an interactive
program to print a string
entered in a pyramid
form. For instance, the
string "object" has to be
displayed as follows:
oobob
jobjeo
bjec
o b j e
c t
17.9 Write an interactive
program to print a
rectangle with diamond
shape gap exactly at the
centre of
that rectangle. Accept
string from standard input
device and print output on
standard output
device. Here is the
sample output when the
string "ob ject-obj ect" is
entered by the user:
Copyrighted material
Chapter 17: Steams Computation with Console 663
object-obj ect
object object
objec bject
obj ject
ob ct
o t
ob ct
obj ect
obje ject
objec bject object
object object-
object
17.10 Write an interactive program to print the salary-slip in the following format:
Centre for Development o f Advanced Computing Bangalore, India - 560 025 Salary-
Slip for the Month of XXXXXX 1996
(SIGNATURE)
17.11 Explain the various methods of performing formated stream I/O operations.
17.12 What are manipulators ? List the various predefined manipulators supported by C++ I/O
streams.
17.13 How are the input and output streams tied using istream. t i e ( ) member function ?
17.14 Write a program to display numbers 0 to 10 in octal, decimal, and hexadecimal systems.
17.15 What are custom manipulators ? Write a custom manipulator for inserting 8 spaces in
output.
17.16 Explain how standard manipulators are implemented.
17.17 Illustrate parameterized custom manipulators using a suitable program.
17.18 Write a program to overload stream operators for reading and displaying the object of a
class Employee. The members of this class include name, emp_no, DateOfBirth, basic,
grade, qualification, etc.
Copyrighted material
52 Mastering C++
has effect on the values of x and y i.e. it exchanges the contents of variables x and y. The above swap (. .}
function can be redefined by using a new parameter passing scheme, call by reference, as follows:
void swapt int & x, int & y ) //by reference {
int t; t = x; X
» y;
y = t;
}
A call to the function swap {)
swap ( x, y ) ;
with integer variables x and y, has effect on the values of x and y variables. It exchanges the contents of the
variables x and y. The body and the call to the function swap appears same as that of call-by-value case, but
has an effect of call-by-pointer. Thus, call by reference combines the flexibility (ease of programming) of call
by value and the power of call by pointer.
The complete program having swap (..) function with call-by-reference mechanism for parameter passing is
listed in swap. cpp.
Run
Enter two integers <a, b>: 2 3 On swapping <a,
b>: 3 2
In main (), the statement
swap ( a, b ) ; is
translated into
swap ( Sc a, St b > ; internally during compilation; the
prototype of the function
void swapt int & x, int & y ) //by reference indicates that the formal parameters are of reference type
and hence, they must be bound to the memory
Copyrighted material
Chapter 18: Streams Computation667
with Files
ofstream: The class of scream supports output operations. It contains open () with default output mode
and inherits put (), seekp (), tellp {}, and write () functions from ostream.
fstream: The class f stream supports simultaneous input and output operations. It contains open () with
default input mode and inherits all the functions from istream and ostream classes through iostream.
Copyrighted material
Chapter 2: Moving from C to C++ 53
location
of the
actual
parameter
. Thus,
any
access
made to
reference
formal
parameter
s in swap
() refers
to the
actual
parameter
s. The
statement
s
y
;
t
;
in the
body of
swap ()
internally
(as
treated by
the
compiler)
have the
following
meaning,
t
"
x
;
/
/
s
t
o
r
e
Copyrighted material
he value pointed by x into
t 2
*x = *y;
pointed by y into location .
pointed by x 9
*y = t;
hold by 't' into location :
pointed by y
because, the formal parameters are S
of reference type and therefore, the y
compiler treats them similar to
n
pointers, but does not allow the
modification of the address stored t
in them. a
x
Void Argument List
A function prototype in C with an
empty argument list, such as o
extern void func () ; f
implies that the argument list of the
declared function is not prototyped;
i
the compiler will not be able to
warn against improper argument n
usage. To declare a function in C l
which has no arguments, the i
keyword void is used, as indicated:
n
extern void func (void); In
C++, the above two declarations e
are equivalent. Because C++
maintains strict type checking, an f
empty argument list is interpreted u
as the absence of any parameter.
n
c
2.11 Inline Functions t
Function execution involves the i
overhead of jumping to and from
the calling statement. Trading of o
this overhead in execution time is n
considerably large whenever a
function is small, and hence in such
E
cases, inline functions can be used.
A function in C++ can be treated as x
a macro if the keyword inline a
precedes its definition. The syntax m
of representing the inline function
is shown in Figure 2.9. p
l
Keyword,
e
function
qualifier :
inline A
ReturnTyp n
e
FunctionN
ame i
(Parameter n
s) {
// body l
of a i
main
n
function
) e
F
i f
g u
u n
r c
e t
Copyrighted material
i function
call.
o
Thereby,
n the
t runtime
overhead
o
for
fi function
n
d
s
q
u
a
r
e
o
f
a
n
u
m
b
e
r
i
s
a
s
f
o
ll
o
w
s
:
inline float square( float x )
{
x
x
;
r
e
t
u
r
n
(
)
;
>
The significant feature of inline
functions is that there is no explicit
function call; the function body is
substituted at the point of inline
Copyrighted material
678 Mastering C++
Run
After execution of the program, the file pay. txt contains the following:
123.45
34.6
5
56.0
0
In main (). the statement
ofstream out_file ( "pay.txt", ios::trunc ); creates the file pay. txt and truncates its contents if the file
already exists. As with the console streams, manipulators can be used with any of the file stream instances.
Default Actions
The file pointers arc set to a suitable location initially based on the mode in which the file is opened.
Fundamentally, a file can be opened in the read mode, write mode nr append mode. The logical location of file
pointers when a file is opened is discussed below ( see Figure 18.7.):
Copyrighted material
Chapter 18: Streams Computation with Files 579
Read-only Mode: when a file is opened in read-only mode, ihe input (gel) pointer is initialized to
point to the beginning of the file, so that the file can bo read from the start.
Write-only Mode: when a file is opened in write-only mode, the existing contents of the file arc
deleted (if a given file already exists) and the output pointer is set to point to the beginning of the
file, so that data can be written from the start.
Append Mode: when a file is opened in append mode, the existing contents of the file remain
unaffected (if a given file already exists) and the output pointer is set to point to the end of the file
so that data can be written (appended) at the end of the existing contents.
-hellc" file
H mode
Read e 1 - 0 W 0 r 1 d
input pointer
■•
-eilo" file
1---
output pointer
Write mode
hello" file
H e mode
Append 1 1 0 W 0 r 1 d
output pointer
Run
Enter String: Obiect-Computina with C++
Output String: Object-Computing with C++
Copyrighted material
Chapter 18: Streams Computation with Files 579
The stream fstream provides the facility to open a file in both read and write modes; so that the
file can be processed randomly by positioning the file pointers.
a
g
e
;
p
u
b
l
i
c
:
/ / this function writes the class's data members to the fil.e void write!
ofstream &os ) {
o s . w r i t e t name,
strleni name ) ) ;
os << ends;
o s . w r i t e t (char")&age, sizeof( age ) ) ;
Copyrighted material
Chapter 18: Streams Computation with Files 579
}
/ / this function reads the class's date member from the f i l e . / / It returns
nonzero i f no errors were encountered while reading int read( ifstream &is
){
i s . get( na
me,
MAXNAM
E, 0 ) ;
namef
is.gcountO
] = 0;
i s . ignore! 1 ) ; / / ignore the NULL terminator in the f i l e , is.readt
(char*)&age, sizeof( age ) ) ; return i s .good( ) ;
}
/ / stream operator, < < overloading
friend ostream & operator « ( ostream &os. Person &b ) ;
/ stream operator » operator overloading friend istream &operator »
{ istream &is, Person &b } ; / / output f i l e stream operator overloading
friend ofstream &operator << ( ofstream &fos. Person &b > (
b
.
w
r
i
t
e
(
f
o
s
r
e
t
u
r
n
f
o
s
;
}
/ / output f i l e stream operator overloading
friend ifstream toperator >> ( ifstream &fos, Person &b )
{
b
.
r
e
a
d
Copyrighted material
Chapter 18: Streams Computation with Files 579
f
o
s
)
;
r
e
t
u
r
n
f
o
s
;
)
);
istream &operator > > ( istream & i s ,
Person &b ) (
cout << 'Name: " ;
i s > > ws; / /
flush input buffer
i s . get( b.name,
MAXNAME ) ;
cout « "Age : ' ;
i s » ws >> b.age;
return is;
}
ostream ^operator « ( ostream
&os. Person &b J {
o
s
«
b
.
n
a
m
e
«
e
n
d
l;
o
s
<
<
b
.a
Copyrighted material
Chapter 18: Streams Computation with Files 579
g
e
<
<
e
n
d
l;
r
et
u
r
n
o
s;
}
v
o
i
d
m
a
i
n
(
)
{
Person p_obj;
/ / open a f i l e in binary mode and write objects to i t ofstream of ile { "person.
txt", i'os : : trunc | ios : :binary ) ; char ch; do
(
cin >> p_obj; / / read object
of ile <<. p_obj; / / write object to the outputs f i l e
cout « "Another ? ' ;
cin » ch; )
while( toupper
{ ch ) = = * Y '
);
ofile.close( ) ;
/ / Output loop, display f i l e content ifstream i f i l e ( "person.txt",
ios::binary ) ; cout « 'The objects written to the f i l e w e r e : . . " « endl; while(
1)(
i f i l e > > p_obj; / / extract person object from f i l e i f (
ifiie.failO ) / / f i l e read f a i l , end-of-file break;
cout « p_obj; / / display person object on console
)
)
As
N
a
m
Copyrighted material
Chapter 18: Streams Computation with Files 579
e
:
T
e
j
a
s
w
i
A
g
e
5
A
n
o
t
h
e
r
N
a
m
e
:
S
a
v
i
t
h
r
i
A
g
e
2
3
A
n
Copyrighted material
Chapter 18: Streams Computation with Files 579
o
t
h
e
r
n
The objects written to the file were: . .
Tejaswi
5
S
a
v
i
t
h
r
i
2
3
/ / fio.cpp: input and output operations on file, random access
•include <iostream.h>
•include <fstream.h>
•define READ_SIZE 6
void main()
{
char reader! READ_SI2E ♦ 1 J;
// fstream constructor, open in binary input and output mode fstream fstr( "test.del",
ios::binary|ios::in|ios::out ); // Write the numbers 0 to 9 to file for< int i = 0; i < 10; i++ )
fstr « i; // Set the write (put) pointer, fstr.seekpt i
) ; fstr << "Hello"; // Set the read (get) pointer.
fstr.seekg( 4 ); fstr.readt reader, READ_SIZE ); reader!
READ_SIZE J = 0; // end of string cout « reader «
endl;
)
Run
llo789
Note thai an instance of fstream has l wo file pointers associated with it: a get pointer used
while reading, and a put file pointer used while writing. The statement
fstr.seekpt 2 ) ; sets
the put pointer to an offset 2.
The program first writes ASCII codes of the digits 0 to 9 to the file test - del. moves the put
pointer by an offset 2 from the beginning of the file and the overwrites the numbers 3 through 6
with the string "Hello'* It then reads 6 characters from the offset 4 into the array reader. The last
line of the program will display these 6 characters, which will be llo789. After all writes arc
completed, the contents of the file test.del will be: 01Hello789
The facility for direct file processing is essential in database applications. They perform
extensive data read, write, update, and search activities. These actions require movement of the
file pointers (get or put) from one position to another. This can be easily performed by using the
seek {), read (), and write () functions.
The location at which the mlh object is stored can be computed using a relation: location = m *
sizeoff object) This specifies Ihe offset at which the object is stored in a file. It can be used to
manipulate the m,h object by using the read() or write () functions.
Copyrighted material
Chapter 18: Streams Computation with Files 579
The program direct. cpp illustrates the mechanism of updating a file by random access. It uses
'he file person.txt to store objects and then these objects can be updated if necessary. The file
H u n t e r s get and put are positioned based on the object to be accessed.
/ / direct.cpp:
accessing objects randomly
•include <fstream.h>
•include <ctype.h> / / For toupper
•include <string.h> / / For strlen
•
d
e
f
i
n
e
M
A
X
N
A
M
E
4
0
c
l
a
s
s
P
e
r
s
o
n
f
private:
char name[ MAXNAME ] ;
i
n
t
a
g
e
;
p
u
b
l
i
Copyrighted material
Chapter 18: Streams Computation with Files 579
c
:
/ / this function writes the class's data members to the f i l e void
write{ ofstream kos )
i
o s . w r i t e ( na
me, strlen( name )
) ; os << ends;
o s . w r i t e t (char*)&age, sizeof( age ) ) ;
}
/ / this function reads the class's date member from the f i l e .
/ / I t returns nonzero i f no errors were encountered while reading.
int readf ifstream &is )
(
is.getf
name,
MAXNAM
E, 0 ) ;
name[ is.gc
ountO ] =
0;
is.ignore{ 1 ) ; / / ignore the NULL terminator in the f i l e ,
i s . readf (char*)&age, sizeof( age ) ) ; return i s . g o o d O ;
}
/ / stream operator, « overloading
friend ostream & operator « { ostream &os, Person &b ) ; / / stream
operator >> operator overloading friend istream ^operator » ( istream
& i s , Person &b ) ; / / output f i l e stream operator overloading
J;
istream ^operator » ( istream & i s ,
Person &b ) {
cout « "Name: " ;
is >> ws; //
flush input buffer
i s . g e t t b.name,
MAXNAME ) ;
cout « "Age : " ;
is » ws » b.age;
return is;
}
ostream &operator « { ostream tos,
Person &b ) {
os << "Name:
" << b.name <<
endl; os « "Age :
" < < b.age « endl;
return os;
void showt
double val ) (
cout « "Double: " << val << endl;
)
void showt char
*val ) {
cout << "String: " << val << endl;
)
Copyrighted material
Chapter 18: Streams Computation with Files 579
i
nt
main
() (
showt 420 ); // calls showt int val );
showt 3.1415 }; // calls showt double val )~,
showt 'Hello World\n!" ); // calls showt char *val ); return( 0 );
)
Bun
Integer:
420 Double:
3.1415 String:
Hello World
In ihe above program, three functions named show () are defined, which only differ in their
argument lists: int, double, or char*. The functions have the same name. The definition of several
functions with the same name is called function overloading.
It is interesting to note the way in which the C++ compiler implements function overloading.
Although, the functions share the same name in the source text (as in the example above, show (J).
the compiler (and hence the linker) uses different names. The conversion of a name in the source
file to an internally used name is called name tnangling. For instance, the C++ compiler might
convert the name void showt int) to the internal name Vshowl, while an analogous function with a
char* argument might be called VshowCP. The actual names which are used internally depend on
the compiler and are not relevant to the programmer, except where these names shown in the
example, a listing of the contents of a function library.
A few remarks concerning function overloading are the following:
♦ The usage of more than one function with the same name, but quite different actions should be
avoided. In the above example, the functions show () are still somewhat related (they print
information on the screen). However, it is also quite possible to define two functions, say
lookup (), one of which would find a name in a list, while the other would determine the video
mode. In this case, the two functions have nothing in common except their name. It would
therefore be more practical to use names which suggest the action; say, findnamet) and
getvidmode ().
♦ C++ does not allow overloaded functions to only differ in their return value. The reason is that
processing (testing) of a function return value is always left to the programmer. For instance, the
fragment
printf ("Hello World!\n"); holds no information concerning the return value of the function
printf () (The return value is, in :his case, an integer value that states the number of printed
characters. This return value is practically
{
/ / f i l e does not exist
}
2. Open fail: opening read-only marked file
ofstream outfile( "myfile.dat" ) ;
i f f Unfile ) / / or i f f infile.badf) )
{
/ / f i l e already exist and marked as read only
)
3. Detecting end of file
whilef !i n f i l e .eof{ ) ) / / processes until end-of-file is reached (
/ / process f i l e
)
4. Read fail
i
nfile.
readf. .
.); iff
Copyrighted material
Chapter 18: Streams Computation with Files 579
infile
.badf
)) {
/ / f i l e cannot be processed further
)
5. Invalid filename
i
nfile.op
enf " | -
*" )
iff !
infile
)
{
/ / invalid f i l e name
}
6. Processing unopened file
i n f i l e . readf. . ) ; / / read file
i f f infile.failf) )
{
/ / f i l e is not opened
>
The program outf ile. cpp illustrates the trapping of all possible errors, which
may be encountered during file processing.
>
c
atchf
Object2
){
Copyrighted material
Chapter 18: Streams Computation with Files 579
Bun
Here is an explicit
argument Hello World!
Copyrighted material
Chapter 18: Streams Computation with Files 579
catch
( . . . )
{
// actions for handling an exception
}
The three dots in the catch(...) indicates that it catches all types of exceptions raised :n its
preceding try-block. The program catal 11. cpp illustrates the mechanism of handling all the
exceptions raised by a single handler.
Copyrighted material
Chapter 18: Streams Computation with Files 579
try
{
cout « "Trying to create object a2(15)...";
array a2(15); // create array, causes
exception cout « "succeeded" « endl; a2[3] = 3;
// valid access
)
catch( arra
y::SIZE ) {
// action for exception
cout « "....Size exceeds allowable Limit" « endl;
)
catch( array::RANGE ) // true if throw is executed in try scope {
// action for exception
cout « "... .Array Reference Out of Range" « endl;
)
)
Run
Maximum array size allowed = 10
Trying to create object al(5)...succeeded
Trying to refer al[5]...succeeded..al[5] * 10
Trying to refer al[15].........Array Reference Out of Range
Trying to create object a2(15).............Size exceeds allowable Limit
terminate()
The function terminate ( ) is invoked when an exception is raised and the handler is
not found. The
Copyrighted material
Chapter 19: Exception Handling 723
the terminate (), the user should define t_func function. This t_func function can be installed by set_terminate
as the termination function. The installation of t_func allows the user to implement any action that is not taken
by abort (). The syntax of the set_terminate function declared in the header file except. h is as follows:
typedef void (*terminate_function)();
terminate_function set_terminateI terminate_function t_func ) ; / / Define your termination scheme
terminate_function my_terminate ( void ) {
// Take actions before terminating // should not
throw exceptions exit(l); // must end somehow
)
/ / Register your termination function set_terminate(
my_terminate ) ;
The program myhand. cpp handles uncaught exceptions with the user specified terminate function.
/ / myhand.cpprAll exceptions are not caught, executes MyTerminate ( )
•include <iostream.h>
•include <except.h>
Class excepl ( > ;
class excep2 {};
void MyTerminate ( )
{
cout « "My Terminate is invoked"; •xit( 1 ) ;
)
void main{) {
■exterminate{ MyTerminate ) ; // sets to our own terminate function try
{
cout « "Throwing uncaught exception\n"; throw excep2{);
)
catch( excepl ) {
/ / action for exception
cout « "Caught exception, excepl\n";
}
// program abort(} here; MyTerminate( ) will be called cout « "I am not
displayed";
)
Run
Throwing uncaught exception My
Terminate is invoked
Bm
M M ; M l M M M M M M j M M M l M M M M M M M M J ! M l M M M M M MM!!!!!! I
.......................................................... . . . . . . . , . . * . . * . , . „ * * * . » .
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
Copyrighted material
Chapter 19: Exception Handling 723
/ / Interact.cpp: interactive program raises exception for improper data •include <iostream.h>
•include <process.h>
const int VEC_SIZE = 10; / / maximum vector s i z e , that can be allocated
class vector
{
private:
int *vec; / / pointer to array for vector elements
int size; / / maximum vector s i z e
public:
class SIZE { ) ; / / Size abstract c l a s s
class RANGE { } ; / / Range abstract class
vector( int
SizeRequest ) {
i f ( SizeRequest <= 0 | j SizeRequest > VEC_SIZE )
throw
SIZEO ;
size =
SizeRequest;
vec = new
int[ size ) ;
J
-vector!) / / destructor
{
delete vec;
)
/ / subscripted operator overloading int
& operator!]( int i ) ;
);
/ / subscripted operator overloading int
& vector::operator!] ( int i ) {
i f ( i < 0 | | i >= s i z e )
throw RANGE!); / / throw abstract
object return v e c f i ] ; / / valid reference
)
void
m
ai
n
(
)
{
int s i z e , data, index;
cout « "Maximum vector size allowed = " « VEC_SIZE << endl;
try
{
cout « 'What is the size o f vector you want to create: " ; cin » s i z e ;
Copyrighted material
Chapter 19: Exception Handling 723
cout << "Trying to create object vector vl of size = " « s i z e ; vector v l ( s i z e ) ; / / create
vector cout << " . . . s u c c e e d e d " << endl;
cout « "Which vector element you want to access (index) : " ; cin » index;
cout « "What is the new value for vl[ w << index << " ] : " ; cin >> data;
cout « "Trying to modify al [ " « index « " ] . . . " ;
vl[index] = data;
cout « "succeeded" « endl;
cout << "New Value of al [ " « index « ■ ] = " « vl[index];
)
catch( vector::SIZE ) {
/ / action for exception cout << "failed" << endl;
cout « "Vector creation size exceeds allowable limit"; exit( 1 ) ;
)
catch( vector: :RANGE ) / / true if throw is executed in try scope (
/ / action for exception cout « "...failed" « endl; cout « "Vector reference out-of-range"; exit ( 1 ) ;
}
}
Bual
Maximum vector size allowed = 10
What is the size of vector you want to create: 5
Trying to create object vector vl of size - 5 . . . succeeded
Which vector element you want to access (index): 2
What is the new value for vl[ 2 ] : 2
Trying to modify al[ 2 ]...succeeded
New Value of al( 2 ] = 7
Run2
Maximum vector size- allowed = 10
What is the size of vector you want to create: £
Trying to create object vector vl of size = 5...succeeded
Which vector element you want to access (index) : 10.
what is the new value for vl( 10 J : 2
Trying to modify al[ 10 ] ...failed
Vector reference out-of-range
Run3
Maximum vector size allowed = 10
What is the size of vector you want to create: 1£ Trying to create object vector vl of size = 15 Vector creation
s i z e exceeds allowable limit
Note:
Runl: All operations are valid, no exception is generated
s_age = m;
*.
virtual int
GetAgetvoid)
{
return s_age;
)
■■
void
m
ai
n
(
)
<
*
int
father_age
; int
son_age;
Father *basep; / / pointer to father objects cout < <
"Enter Age o f Father: " ; c i n » father_age;
try
(
Copyrighted material
Chapter 19: Exception Handling 723
Run1
Enter Age o f Father:
15. Father's Age:
4 5 Enter Age of
Son: 2£ Son's Age:
20
Bun2
Enter Age of Father:
2J2 Father's Age:
2 0 matrix <T>
operator -
( matrix <T> b ) ;
matrix <T>
operator *
( matrix <T> b ) ;
void operator -
( matrix <T> b ) ;
int operator ==
( matrix <T> b ) ;
};
template <class T>
matrix<T> matrix<T>::operator + { matrix <T> b ) {
matrix <T> c ( MaxRow, MaxCol ) ; int i , j ;
i f ( MaxRow ! = b . MaxRow | | MaxCol ! = b . MaxCol )
throw MatErrorO; f o r ( i = 0 ; i < MaxRow; i +
+ )
f o r ( j = 0 ; j < MaxCol; j++ )
c . M a t P t r [ i J [ j ] = M a t P t r ( i ) [ j ] + b.MatPtr[ i ] [ j ] ; return( c ) ;
)
template <class T>
matrix <T> matrix<T>: : operator - ( matrix <T> b ) {
matrix <T> c { MaxRow, MaxCol ) ; int i , j ;
i f ( MaxRow ! = b . MaxRow | | MaxCol • = b . MaxCol )
throw MatErrorO; f o r ( i = 0 ; i < MaxRow; i+
+}
for( j = 0 ; j < MaxCol; j++ )
c . M a t P t r t i ] [ j ] = M a t P t r [ i ] [ j ) - b . M a t P t r [ i ) [ j ] ; return( c ) ;
}
template <class T>
matrix <T> matrix<T>::operator * ( matrix <T> b ) {
matrix <T> c { MaxRow, b . MaxCol ) ; int i , j , k ;
i f ( MaxCol ! = b . MaxRow )
Copyrighted material
Chapter 19: Exception Handling 723
Copyrighted material
Chapter 19: Exception Handling 723
i = i + k [ O V - > i = i - j ; signal OW ) ;
end
The semantic definition of the assignment operator = specifies that whenever the evaluation
of the right hand side expression terminates exceptionally (overflow occurs, OV), no new value is
assigned to the left hand side variable. Then, P will terminate exceptionally by executing the
recovery block (if it exists) and signals an OW (overflow word) exception label in the final state.
Data Case 1 : i <- MaxValue, j <- MaxValue, and k < - (-MaxValue) Operation i + j +k (as per data case 1)
is valid, but i + j exceeds the representation limit leading to an exception.
Version 2:
proc P signal OW begin
i = i + k [ OV - > signal OW ] ;
i = i + j [ OV - > i = i - k ; signal OW ] ;
end
This version terminates with a valid final state for the data case 1. DataCase2i i < - MaxValue, j
(MaxValue) Operation i + j +k (as per data case 2) is valid, but (i+k)
< - (-MaxValue), and k < -
exceeds the representation limit leading to an exception.
Version 3:
proc P signal OW begin
j = j + k [ OV - > signal OW ] ;
i = i + j [ OV - > j = j - k ; signal OW ] ;
end
This version terminates with a valid final state for the data case 1 and case 2.
Copyrighted material
Chapter 2: Moving from C to 59
C++
v
o
i
d
P
r
i
n
t
L
i
n
e
t
c
h
a
r
c
h
,
i
n
t
R
e
p
e
a
t
C
o
u
n
t
,
i
n
t
n
L
i
n
e
s
{
int i,
j;
fort j
= 0;
j <
nLin
es;
j++ )
(
Copyrighted material
cout « endl; as 1,
fort thereby
i the new
function
=
docs the
0 same
; operation
as that of
i the old
one.
< Thus,
default
R
argument
e
p s feature
e can be
a potentiall
t y utilized
C in
o extending
u the
n function
t
without
;
modifyin
i g the old
+ code.
+ Note that
all
> argument
s in a
c multiple
o
u argument
t function
need not
« have
default
c values.
h
;
) 2.14
} Keyw
Bun ord
typed
■ I ............1 1 1 1 1 1
11 i 1 1 i 111 i
ef
11111111111 1 1
1 111111111111 1 111 i 11 i i The
11 i i i i i keyword
typedef is
R
allowed
RRRRRRRRRRRRRRRRRRRRRR
RRRRRRRRRRRRRRRRRRRRRR in C++,
RRRRRRRRRR but no
&&&&&&&&&&&&&&&&&&&&&&&&& longer
&&&&&&&&&&&&&&&&&&&&&&&&& necessary
The following statements in the , when it
above two programs is used as
PrintL / / uses both a prefix
inet);
PrintL
)default
arguments / /
in enum,
struct, or
ine t assumes 2nd union
'!
PrintL fargument as
default / /
declaratio
inet ' * 4 ignores default ns. This
PrintL 0 arguments / / is
inet ) ignores default illustrated
'R ; arguments in the
5
following
5
} example:
;
arc the same. Although, the
functionality of the function
PrintLine, is enhanced indefarg2
.cpp program, the old code
referring to it remains unaffected in
terms of its functionality; the
compiler supplies the last argument
Copyrighted material
struct somestruct a
{ t
i
.
n
t
I
a n
;
d C
o ,
u
b
l t
e h
e
d
;
char string [ 8 0 ] ; s
a
When a struct, enum, or any other m
compound type is defined, the tag e
of this type can be used as type
name (somestruct is the tag in the
v
above example). For instance, the
a
statement
r
s
i
o
a
m
b
e
l
s
e
t
r
i
u
s
c
t
d
w
e
h
f
a
i
t;
n
d
e
e
d
f
i
a
n
s
e
s
s
truct
t
somestru
h ct what;
e Thus, the
s use of
t keyword
r struct in
u the
c structure
t variable
u is default.
In C++,
r
the
e
members
v of the
a structure
r variables
i are
a accessed
b similar to
l C. The
e statement
w wha 3.1
t.d 415
h = ;
Copyrighted material
738 Mastering C++
Copyrighted material
738 Mastering C++
catch( O
VERFL
OW ) (
cout << "Error: Overflow. All versions failed" « endl;
)
}
)
return result;
}
v
o
i
d
m
a
i
n
(
)
(
int result;
cout << "Sum o f 7 , - 3 , 2 computation..." « endl;
result - sum( 7 , - 3 , 2 ) ; / / versionl computes
cout << "Sum = " << result << endl;
cout « "Sum o f 7 , 2 , - 3 computation..." « endl;
result = sum( 7 , 2 , - 3 > ; / / version2 computes
cout « "Sum = " « result « endl;
/ / Device data such that version-3 succeeds
cout « "Sum of 3 , 3 , 2 computation..." « endl;
result = sum{ 3 , 3 , 2 ) ; / / all version fails
cout « "Sum = " « result « endl;
}
Bun
Sum o f 1, - 3 , 2
computation. . . Version-1
succeeds Sum = 6
Sum of 7 , 2 , - 3
computation... Version-1
fails
Version-2 succeeds Sum
=6
Sum of 3 , 3 , 2 computation...
Version-1 fails Version-2 f a i l s
Error: Overflow. All versions failed Sum =
8
Copyrighted material
738 Mastering C++
Bml
How many bytes to be allocate: 100
Memory allocation success, address = OxlSbe
Copyrighted material
Chapter 20: OO Analysis, Design and Development 755
apart at the end of the project and individuals are scattered and reassigned to other projects or they might
change organization (which is most common in software industry). Hence, peopleware approaches to
software productivity often achieve results several times greater than technical approaches.
Object A Object C
Input Output
Method
Object B Object D
A similar structure could be a part of the painting program used to represent a pixel in the drawing.
The following are the points to be noted about structures:
• The function draw ( ) . which occurs in the structure body is only a declaration. The actual code of the
function, or in other words, the actions to be performed by the function arc located elsewhere in the
code section of the program. Member function can also be defined within the body of a structure.
♦ The size of the structure point is just two integers. Though a function is declared in the structure, its
size remains unaffected. The compiler implements this behavior by allowing the function draw ( ) to
be known only in the context of the point structure.
The point structure could be used as follows:
point a , b; I I two points on the screen
a.x = 0; II define f i r s t dot
a . y = 10; II and draw it
a.draw ( ) ;
b = a; I I copy a to b
b . y = 20; II redefine y-coordinate
b.draw ( ) ; I I and draw i t
The function draw (). which is a part of the structure, is selected in a manner similar to the selection of
data fields; i.e., using the field selector operator ( . ) with value structures or - > with pointers to
structures.
Copyrighted material
struct date
structure data
members
) structure
member I
function
Copyrighted material
762 Mastering C++
C Class
Certificatio
n
Figure 20.10: Steps in class design and development
A design framework states that every class should be designed so as to be amenable for use as
a component by other classes. The class design principles focuses on design for reuse and it
includes the following:
I. Design of (abstract) class rather than one shot objects.
?. Design of class interfaces (accessors, methods) rather than of attributes and transitions. ?
Standardization of interfaces, leading to the specification of interoperable subclasses and the cre-
ation of applications frameworks.
Design of reliable interaction protocols, often supplementing pure event-driven models.
values for the coordinates of the center of the circle and one value for the radius. Analogous to the
point structure, a draw() could be declared in the circle structure which would draw the circle.
The program date2 .cpp is C++ equivalent of the earlier program datel .cpp. It illustrates the
concept of associating functions operating on structure members as shown in Figure 2.10. The
structure date has both the data members and functions operating on them. The user accesses the
member functions additionally, when compared to C's structure using the dot operator.
Copyrighted material
762 Mastering C++
)
};
v
oid
mai
n{ )
{
date dl = ( - 2 6 ,
3 , 1958 ) ; date d2 =
( 14, 4 , 1971 ) ; date
d3 = ( 1, 9. 1973
};
cout < < "Birth Date of the First Author: " ;
dl.show( ) ;
cout « "Birth Date of the Second Author: ■ ;
d2 .showO ;
cout < < "Birth Date of the Third Author: " ;
d3.show( ) ;
)
Run
Birth Date of the First Author: 26-3-1958
Birth Date of the Second Author: 14-4-1971
Birth Date of the Third Author: 1-9-1973
In m a i n ( ) , the statements
d
l
.
s
h
o
w
(
}
;
d
2
.
s
h
o
w
(
)
;
d
3
.
s
h
o
w
{
)
;
invoke the function s h o w ' ) defined in the structure date.
Copyrighted material
762 Mastering C++
Example:
fort i =
0 ; i < n;
i++ ) (
i f ( wants_to_terminate_loop )
break; / / transfers control to the next statement outside loop
)
catch: capture
exception thrown
Syntax:
catch( <exception-
object> )
Description: An exception thrown in the program is caught by the catch statement.
It follows try statement and is responsible for taking corrective actions in response
to an exception.
Example:
class div_by_zero { ); / / empty class
Copyrighted material
776 Mastering C++
to be its friend, should explicitly declare it as its friend. Friend function or class cannot access members of a
class to which it is a friend directly; it has to access them using class objects.
Example:
class
stars {
private:
class
);
class galaxy (
void
func() {
stars s i ;
s i . magnitude = 100; / / valid since galaxy is a friend of stars
}
>;
The above declaration states that, the class galaxy can access all the members of the class s t a r s but not vice-
versa.
)f
Copyrighted material
776 Mastering C++
The syntax of template function is similar to a normal function, except that it uses variables whose data
types are not known until they are invoked. Such unknown data types (generic data types) are resolved by the
compiler and are expanded to the respective data types (depending on the data type of actual parameters in a
function call statement). A call to a template function is similar to that of a normal function. It can be called
with arguments of any data-type. The complier will create functions internally without the user intervention,
depending on the data types of the input parameters. The function template for finding the maximum of two
numbers is shown below:
template <class T>
T max{ T a, T b ) (
if( a > b )
return a;
else
return b;
)
Copyrighted material
776 Mastering C++
The program mswap. cpp illustrates the need for function templates. I t defines multiple swap functions for
swapping the values of different data types.
Copyrighted material
Appendix B: C++ Library Functions
Function Description Include File
abort( ) abnormally terminates a program atdlib.fa
aba() return* Ihe absolute value of an integer aith.h
acoaf) calculates the arc cosine matb. b
•■ctiaat) converts dale and time 10 ASCII tiBM. b
talad calculaies the arc sine saath.b
ictii a condi::'Mi and possibly aborts aaaaxt.h
atan() calculates the arc tangent atatb.b
atan2() calculates the arc tangent of y/x n int h . h
ataxitt) registers an exit function ■tdlib.b
ato«(> converts a string to a floating-point number autb.h
atoiO converts a string to an integer ateUib.h
■toll) converts a string 10 a long integer • t d l i b. b
baaarcb( ) binary search of an array • t d l i b. b
callocO allocates main memory • t d l i b. b
cailO rounds up saath.b
claar*rr() resets error indication ■tdio.b
clock( ) determines processor time t 1M . b
coi() calculates the cosine of a value rnath.b
coab() calculates the hyperbolic cosine of a value ma t h. h
otimaO converts date and lime to a string tiaa. h
•Kit( ) terminates program • t d l i b. h
CabaO returns the absolute value of a floating-point number sutb.b
f c l o a e t) closes a stream • t d i o. b
f«cf : detects end-of-file on a stream ■tdio.b
t arror( ) detects errors in a stream • t d i o. b
£ f luaht) flushes a stream ■tdio.b
fgatcf.) gets character from stream ■tdio.b
fgatpo«<) gets OK current file pointer ■tdio.b
fsataO gets a string from a stream ■tdio.b
floorO rounds down sutb.b
fmod() calculates x modulo y. the remainder of xJy sutb.b
t opanf) opens a stream • t l i o. b
fprintf< > writes formatted output to a stream ■tdio.b
fpute( ) puts a character on a stream ■tdio.b
fputaO outputs a string on a stream ■tdio.b
Ir e a d t ) reads data from a stream ■tdio.b
fraa<) free allocated Mock alloc.b
':«-;«"■ ) associates a new file with an open stream ■tdio.b
fraxpf) splits a double number into its mantissa and exponent sutb.b
facanf< ) icans and formats mpui from a stream ■tdio.b
MO repositions a file pointer on a stream ■tdio.b
faatpoal) positions the file pointer of a stream ■tdio.h
fatat() gels file statistics ■ys\atat.h
ftalK) returns the current file pointer ■tdio.b
fwritaO writes to a stream ■tdio.b
flatcO gets a character from a stream • t d i o. b
gatcbarO gets a character from stdin ■tdio.b
gataO gets a suing from stdin ■tdio.b
iaalnuat ) character classification macro ctypa.b
laalpbaO character classification macro ctypa.b
iaaaciiO character classification macro ctypa.b
LacntrK) character classification macro ctypa.h
*adigit( ) character classification macro ctypa.b
i«graph() character classification macro ctypa.b
ii l o w a r ( ) character classification macro ctypa.h
iaprint( ) character classification macro ctypa.h
iapunct( ) character classification macro ctypa.h
iaapacef.) character classification macro ctypa.b
iauppar() character classification macro ctypa.b
iexdigit( ) character classification macro ctypa.h
7XX
Copyrighted material
Appendix B: C++Library Functions 789
Copyrighted material
Appendix D: ASCII Character
Continued... ►
Set
Copyrighted material
245 Mastering C++
Continued... ►
Appendix E: Bibliography
j 1 j Alan Joch, Nine ways to make your code more reliable — How Software Doesn't Work ?, Byte
Magazine 49-60p. October 1995. [2| Bernd Muller, Is Object-Oriented Programming Structured
Programming ?, ACM SIGPLAN
Notices. Volume 28, No. 9, September 1993. (3J Bjarne Stroustrup, The C+ + Programming
Language (2nd Edition), Addison Wesley, 1991. [4] Bjarne Stroustrup, The Design and Evolution of C+
+, Addison Wesley, 1994. [5] Bruce Eckel, Using C++, Osborne McGraw Hill, 1989.
[6] Capper, Colgate, Hunter, and James, The impact of object-oriented technology on software quality: Three
case histories, IBM Systems Journal, Volume 33, No. 1,1994.
[7] D. Dechanpeaur et al. The Process of Object Oriented Design, Seventh Annual Conference on Object-
Oriented Programming, System, Language, and Applications (OOPSLA), 1992.
[8] Data Quest Magazine, OOP - New Software Paradigm, 1-15 April, 1995, India.
[9] E Balagurusamy, Object-Oriented Programming with C++, Tata McGraw Hill Publications, 1996.
[10] Edmund X Dejesus.S/g OOP, No Oops, Byte, August 1995.
(11] Edward Yourdon, Object-Oriented Systems Design, Prentice Hall Inc, 1994.
[12] Harald M Muller, Ten Rules for Handling Exceptions Handling Successfully, C++ Report, Jan. 1996.
[13] Henda Hodjami, A Reuse approach based on Object-Orientation, Software Engineering Notes,
Proceedings of the Symposium on Software Reusability, August 1995.
Copyrighted material
246 Mastering C++
[14] James and Josephine, Reuse Through Inheritance, Software Engineering Notes, Proceedings of the
Symposium on Software Reusability, August 1995.
[15] Keith Gorlen, C++ Under UNIX, UNIX Papers, Waite Groups.
[ 16] Margaret A. Ellis and Bjarne Stroustrup, The Annotated C+ + Reference Manual, Addison-Wesley,
Reading, MA, 1990, ISBN 0-201-51459-1. [17] Markku Sakkinen, The Darker Side of C++
Revisited, Department of Computer Science and
Information Systems, University of Jyvaskyla, Finland. [18] Nicholas Wilt, Templates in C++,
Supplement to Dr. Dobb's Journal, December 1992. [ 19] Rajkumar, Fault Tolerant Computing, A
Seminar Report, Bangalore University, 1995. [20] Randall Hyde, Object-Oriented Programming in
Assembly Language, Dr. Dobb's Journal, Mar. 1990. [21] Tim Rentsch, Object-Oriented Programming,
SIGPLAN Notices, September, 1992. [22] Robert G Fichman and Chris F Kemerer, Object-Oriented and
Conventional Analysus and Design
Methodologies, IEEE Computer, 1992. [23] Robert Lafore, Object-Oriented Programming in Turbo
C++, Waite Group, 1992. [24] Steven J, A Technique for Tracing Memory Leaks in C++, NCR
Microelectronics, Colorado. [25] SunSoft, C + + Selected Reading, Object-Oriented Programming, August
1994. [26] Turbo C++, Library Reference Manual, Borland International Inc., 1990 [27] Venugopal K R
and Vimala H S, Programming with Fortran, Tata McGraw Hill, India, 1994. [ 28 ] Venugopal K R and
Vimala H S, Programming with Pascal and C, Tata McGraw Hill, India, 1994. [29] Venugopal K R and
Rajkumar, Microprocessorx86 Programming, BPB Publications, India, 1995. [30] Venugopal K R and
Maya, Programming with Pascal, Tata McGraw Hill, India, 1997. [31 ] Venugopal K R and Sudeep,
Programming with C, Tata McGraw Hill, India, 1997.
800 Appendix F: Index
B D
Bibliography, 222 binary, 120 data, 105
mode files, 683 decomposition, 313
operator overloading, 432 binding, demotion, 122
262 entering into structures, 242
early, 22 hiding, 322=332
late, 2Q.22, 83 bits. 12Q passing to functions, 198-201
bitwise operators, 12Qrl22 bound promotion, 122
checking arrays, 121 break statement, returning from functions, 201-203 members, 313-
158-160 bubble sort, 174-176 314 datatypes, 103
charaeter(char), 103
c double precision floating point,
double, 103
calling functions, 128 enumerated(enum), 136-138 floating
function calls with arguments, 126 point(float), 103 integer(int), 103
cast operator, 122 character(char) long double precision floating point, (long
variable type, 103 character set, 100 double), 103
closing files, 662 classes, 113^6Q long integer(long), 103
declaration of, 114 short integer(short), 103
instantiation, 313.316 structure, 232
private, 314.331 void, 234 destructors, -i71-373 delete
protected, 314.332 operator, 69,403 delegation, 27.562-566 Jo-while
public, 314.332 loop, 156-158 default arguments, 210-212 default
templates, 4 class design, 761-764 constructor, 365.370 driver function, 763
class template, 610 client server model, dynamic construction, 383 dynamic destruction,
112 COBRA, 22Q 383 dynamic binding, 570. 57? dynamic objects,
command line arguments, 200 comments, 400-431
33.40-41 command line compilation, 35
composition, 562-566
conditional operator(ternary operator),
126r 128
constant object, 323
constants, 131-134
constructors, 264-3RO
Copyrighted material
804 Appendix F: Index
u
unary operator overloading, 417
unions, 259-266
unsigned (unsigned)variable type, 103
unsigned integer variable type, 103
v
variable, 102
definition, 104 extent, 223
initialization, 104
scope, 223 virtual destructors, 589
virtual functions, 87.570-594 virtual
pointer(VPTR), 591
vinualtable(VTBL), 591 void, 234
void pointer, 226=223
w
water falling model, 749 while loop.
154-156 wild pointer. 307-310 world
wide web, 30
Chapter 1: Object-Oriented Paradigm 17
1.10 Inheritance
Inheritance is the process, by which one object can acquire (he properties of another. It allows
the declaration and implementation of one class to be based on an existing class. Inheritance is
the most promising concept of OOP. which helps realize the goal of constructing software
systems from reusable parts, rather than hand coding every system from scratch. Inheritance not
only supports reuse across systems, but also directly facilitates extensibility within a given
system. Inheritance coupled with polymorphism and dynamic binding, minimizes the amount of
existing code to be modified while enhancing a system.
To understand inheritance, consider the simple example shown i n Figure 1.15. When the
class Child inherits the class Parent, the class Child is referred to as derived class (sub-class), and
the class Parent as a base class (super-class). In this case, the class Child has two parts, a derived
part and an incremental part. The derived part is inherited from (he class Parent. The incremental
part is the new code written specifically for the class Child. In general, a feature of Parent may be
renamed, rc-implemcntcd, duplicated, voided (nullified), have its visibility status changed or
subjected to almost any other kind of transformation when it is mapped from Parent to Child. The
inheritance relation is often called the is-a relation. This is because when the class Child inherits
the base class Parent, it acquires all the properties of the Parent class. It can also have its own
properties, i n addition to those acquired from its Parent. This is an example of single inheritance;
the child class has inherited proper-tics from only one base class.
Copyrighted material
70 Mastering C++
totally
invisible
to the
user.
Similarly,
the
compiler
translates
the
following
calls
s
w
a
p
t
a
,
)
;
/
/
c
o
m
p
i
l
e
r
c
r
e
a
t
e
s
s
w
a
p
t
i
n
t
&
x
,
i
n
c
&
y
)
;
s
w
a
p
t
i
Copyrighted material
c, d ); // deallocati
compiler creates on
swapt float &x, respectiv
float &y );
ely.
into appropriate functions (if
necessary), and calls them based
new
on their input parameter data
types. Operator
The new
operator
Template Function
offers
Overloading dynamic
A template function can be storage
overloaded in two ways - (i) by allocation
other functions of its name or (ii) similar to
by other template functions of the
the same name. Overloading standard
resolution for functions and library
template functions can be done function
in the following three steps: malloc. It
Copyrighted mat
70 Mastering C++
ation in C and t
C++
2 t
. o
f
d r
e e
e
l t
e (
t d
o
e
u
b
b le
; *
).
d
i )
s ;
4
e .
q delete
u c
i
i
t
v
y
a
;
l
e
i
n
s
t
e
t q
o u
freet (float i
*) b ) ; v
3 a
. l
delete e
d n
; t
i t
s o
f
r
e e
q e
u
i
v
a
l
e
n
i
Copyrighted material
t (char * } c i t y w
); o
5
. v
e
delete date_ptr;
c
i t
s o
r
s
e
q t
u i
i n
v c
l
a
u
l d
e e
n
t <
i
o
t s
o t
f r e e t (struct r
date * ) date_ptr e
); a
The program vector, m
cpp illustrates the concept .
of dynamic allocation and h
deallocation using new and >
delete operators. void
AddVec
/ tors( int
/ * a , int
* b , int
v * c , int
size )
e
(
c
t for
o (
r
. i
c n
p t
p
: i
-
a
d =
d
i 0
t ;
i
o i
n
<
o
f s
i
t z
Copyrighted mat
70 Mastering C++
e
; >
>
i
v
+ e
+ c
t
) o
r
c [
[ i
i ]
;
]
)
void
=
ShowVe
ctort int
a 'vector,
[ int s i z e
i )
] {
for
+ {
b i
[ n
t
i
l i
;
) =
void ReadVectort int
*vector, int s i z e I 0
{ ;
for
i i
i <
n
t s
i
i z
e
= ;
0 i
; +
+
i
)
<
c
s o
i u
z t
e
; <
<
i
+ v
+ e
c
) t
o
c r
i [
n i
i
Copyrighted material
]
S
< i
< z
e
" ,
■
o
;
-
)
f
v
o
V
i
e
d
c
t
m
o
a
r
i
:
n
(
"
)
;
{
c
i
i
n
n
t
>
v
>
e
c
v
_
e
s
c
i
_
z
s
e
i
;
z
e
i
;
n
//
t
allo
cate
*
me
x
mor
,
y
for
*
all
y
the
,
thre
e
*
vect
z
ors
;
x=
c
new
o
int [
u
vec_
t
size
j;
«
// x
beco
"
E
n
t
e
r
Copyrighted mat
70 Mastering C++
mes array of s i z e
vec_size
y = new int [ vec_size ] ;
/ / y becomes array of
size vec_size
z = new int [ vec_size ] ;
/ / z becomes array o f
size vec_size
cout < < "Enter
elements of vector x :
";
ReadVector( x , vec_size
);
cout < < "Enter
elements of vector y :
";
ReadVector( y , vec_size
);
AddVectors ( x , y , z ,
vec_size ) ; / / z = x+y
i
Copyrighted material
C++ at a Glance
3.1 Introduction
The C++ language evolved as a result of extensions and enhancements to C. It has efficient memory
management techniques, provisions for building new concepts, and a new style of program analysis
and design. The reason for retaining C as a subset is its popularity among programmers, and
moreover, millions of lines of code already written in C can be directly moved to C++ without
rewriting. The other advantages are: the syntax and structure of many statements of C closely
resemble the actual operation on the computer's internal registers and allow to produce fast
executable code.
The most interesting features of C++ are those which support a new style of programming
known as object-oriented programming. I t emphasizes on data decomposition rather than algorithm
decomposition. OOP is generally useful for any kind of application, but it is particularly suited for
interactive computer graphics, simulations, databases, artificial intelligence, high-performance
computing, and system programming applications. This chapter presents the first impression of C++
with its features of object-oriented programming.
C++ as an object oriented programming language supports modular programming and enables
easy maintainability. The most prominent features of C++ that provide a foundation for data
abstraction and object-oriented programming are the following:
• Data Encapsulation and Abstraction: Classes
• Inheritance: Derived Class
♦ Polymorphism: Operator Overloading
• Friend Functions
♦ Polymorphism: Virtual Functions
• Generic Classes: Class Templates
♦ Exception Handling
♦ Streams Computation
Copyrighted material
Chapter 3: C++ at a 77
Glance
Class
es are
syntactica
lly, an
extension
of
structures
. The
differenc
e is that,
all the
members
of
structures
are public
by
default,
whereas
members
of classes
are
private
by
default.
Class
follows
the
principle
of all the
informatio
n about a
module
should be
private to
the
module
unless it is
specificall
y declared
public.
Membe
r
Functio
ns
The data
members
of a class
must be
declared
within
the body
of a class,
whereas
the
member
functions
of a class
can be
defined
in one of
the
following
ways:
♦
Insid
e the
class
body
Copyrighted material
Mastering C++
Copyrighted material
/ N
/ o
d *
i
s ■
p
l «
a
y r
o
d l
a l
t _
a n
o
m
e «
m
b e
e n
r d
s l
;
o
n c
o
t u
h t
e
<
c <
o
n "
s N
o a
l m
e e
s =
c
r *
e
e «
n
n
v a
o m
i e
d
<
s <
t
u e
d n
e d
n l
t ;
:
: void
o main ( )
u
t stude
d nt
a si;
t //
a first
( objec
) t/vari
able
c of
o class
u stude
t nt
stude
< nt
< s2;
//
' secon
R d
o objec
l
l
Copyrighted material
Mastering C++
t/variable of class j
student k
sl.setdatat 1, u
"Tejaswi" ) ; // m
object s i calls member a
function setdata r
s2.setdata( 10, In the
"Rajkumar' ) ; / / class
c a l l s member function student,
setdata the
cout « "Student prototype
d e t a i l s . . . " < < endl; of
s i .outdata( ) ; // member
object si calls member functions
function outdata* setdata
s 2 .outdata( ) ; // and
o b j e c t s2 c a l l s outdata
member function outdata are
1 declared
Hun within
S the body
t of the
u class and
d they are
e defined
n outside
t
the body
d of the
e class. In
t the
a declarator
i void
l student::o
s utdataO
.
student
. : :
. indicates
that the
R function
o
outdata
l
l (),
belongs
N to the
o class
student
=
and it is a
1 member
function
N of the
a class
m student.
e
= 3.3
T Inherit
e ance-
j
a Derive
s d
w
i Class
es
R
o Inheritan
l ce is a
l technique
of
N organizin
o g
informati
=
on in the
1 hierarchic
0 al form.
It is
N similar to
a a child
m inheriting
e the
features
=
such as
R beauty of
a the
Copyrighted material
mother and intelligence of the and
father. It is an important downwa
feature of object oriented
programming that allows to rd
extend and reuse existing code countin
without requiring to rewrite it g
from scratch. Inheritance capabili
involves derivation of new ty
classes from the existing ones,
thus enabling the creation of a #includ
hierarchy of classes, similar to e
the concepts of class and <iostrea
subclass in the real world. A m.h>
new class created using an
class
existing class is called the
derived class. This process is counter
called inheritance. The {
derived class inherits the prot
members - both data and ecte
functions of the base class. It d: //
can also modify or add to the
Not
members of a base class.
Inheritance allows a hierarchy e: i t
of classes to be derived. is
priv
Derived classes, inherit data
members and member ate
functions from their base in
classes, and can be enhanced CO
by adding other data members UN
and member functions. TE
Recall that the program Rl.
counterl. cpp discussed above, CP
uses the class counter as a P
general purpose counter i
variable. A counter could be
n
incremented or decremented.
The counter class can be t
extended to support
downward counting. It can be v
achieved by either modifying a
the counter class or by l
deriving a new class called u
NewCounter from the counter
class. The program counter2 .
e
cpp is an extended version of ;
the previous program and has
two classes, one, counter as a /
base class and two, /
NewCounter as a derived
class. The private members of
a base class cannot be c
inherited. o
u
C++ supports another
access specifier called n
protected. Its access privileges t
are similar to private except e
that they are accessible to its r
derived classes. Protected
access privilege is used when v
members in base class's
a
section arc to be treated as
private and they must be l
inheritable by a derived class. u
The public members of the e
base class are accessible to the pub
derived class, but the private lic:
members of the base cldss are
c
not. However, the protected
members of the base class are o
accessible to the derived class, u
but they are private to all n
other classes.
t
e
Chapter 3: C+ 7
r
+ at a Glance 9
{
)
/ / counter2.Cpp: new
counter having upward /
Copyrighted material
Mastering C++
/ N o argument u
constructor n
{ t
value = 0 ; / / e
i n i t i a l i z e counter r
value to zero !
)
counter! int val )
i
n
with one
t
argument
{
v
value = val;
initialize a
counter value l
) )
int GetCounterO
:
{
return value; c
} o
void u p ( ) u
/ / i n c r e m e nnt
counter t
{ e
value * value r
+ 1; !
)
); v
/ / NewCounter is a
derived from the old l
c l a s s counter publically
)
class NewCounter: public
counter
{
{
public: )
N v
e o
i
w
d
C
o
d
u
o
n w
t n
e O
r
( /
) /
:
d
c e
o c
u r
n e
t m
e e
r n
( t
)
c
{ o
u
)
n
N t
e e
w r
C {
o
Copyrighted material
value = value
- 1; / /
decrement
counter
)
>;
v
o
i
d
m
a
i
n
{
)
(
NewCounter
counter1 ;
no argument
constructor
NewCounter counter2
- 1; / / c a l l s 1
argument constructor
cout « "counterl
initially = ■ «
counterl.GetCounter(
) < < endl;
cout « "counter2
initially = ■ «
counter2.GetCounter
{ ) « endl;
/ / increment counter
counterl. u p < ) ;
counter2. u p ( ) ;
cout < < 'counterl on
increment = ■ <<
counterl .GetCounter
( ) << endl; cout «
"counter2 on
increment = " «
counter2 .GetCounter
( ) « endl; / /
decrement counter
counterl.down( ) ;
Copyrighted material
Chapter 3: C++ at a 83
Glance
coun
ter
coun
ter2
=1;
//
calls
1
argu
men
t
cons
truct
or
cout
«
"cou
nterl
initi
ally
="«
coun
terl-
Get
Cou
nter
()
<<
endl;
cout
<<
"cou
nter
2
init
iall
y ='
«
coun
ter2.
Get
Cou
nter
O <<
endl;
//
incr
eme
nt
coun
ter
-
♦cou
nterl
;
coun
ter2
++;
cout
«
"cou
nterl
on
incre
ment
="«
coun
terl .
Get
Cou
nter
{) «
endl;
cout
«
"cou
nter
2 on
incre
ment = " « o
counter2.GetCounter' u
) << endl; n
/ / decrement counter t
--counterl; e
counter2--; r
cout < < "counterl on l
decrement = " < < ;
counterl .GetCounter
( ) « endl; cout << c
"counter2 on o
decrement = " << u
counter2.GetCounter( n
); t
e
r
Run 2
counterl initially = 0 -
counter2 initially = 1 -
counterl on increment = ;
1 it calls
counter2 on increment = the
2
counterl on decrement = overloa
0 ded
counter2 on decrement = operato
1 r
function
The word operator is a defined
keyword. It is preceded in the
by the return type void. user-
The operator to be defined
overloaded is class. It
immediately written after can be
the keyword operator, observe
followed by the void d that
function symbol as the
operator++ ( ) . This function
declarator syntax informs body of
the compiler to call this an
member function overloa
whenever the ++ ded and
operator is encountered, a non-
provided its operand is of overloa
type counter. ded
The statement in the operato
class counter r
void // function
operator incremen is same;
++() t counter the only
overloads the increment change
operator (++■) to operate is in the
function
on the user defined data
prototy
type. When the compiler
pe and
encounters statements method
such as of
++counterl; calling.
counter2 + + ; For
it calls the overloaded instance
operator function defined , the
in the user-defined class stateme
(see Figure 3.3). The state- nt in
ment in the class counter counter
void // 2 .cpp
operator--
decremen c
O
t counter o
overloads the decrement u
operator ( - - ) to operate n
on objects of the user
t
defined data type. When
the compiler encounters e
statements such as r
- 2
- .
c u
Copyrighted material
p n
( t
) e
; r
2
c +
a +
n ;
b i
e n
r t
e h
p e
l
a a
c b
e o
d v
e
b
y p
r
a o
g
m r
o a
r m
e .
r
e
a
d
a
b
l
e
e
q
u
i
v
a
l
e
n
t
s
t
a
t
e
m
e
n
t
:
c
o
u