Object Oriented Programming - C++ (DCA1203)
Object Oriented Programming - C++ (DCA1203)
1.1 Introduction
C++ is a general-purpose Object Oriented Programming (OOP) language.
C++ includes features of object-oriented programming as well as
conventional procedural programming. The major aim of developing object-
oriented programming language is to remove some of the flaws
encountered in programming a language of procedural approach. Object-
Oriented Programming enables one to put data and functions in one
container. This container is referred to as an object. An object enables you
to model your application as closely as possible to the real world.
In this unit, we will discuss the basic features of object-oriented
programming. In this unit, we also discuss the evolution of programming
Some of the languages that use object oriented programming approach are
C++, Java, Csharp, Smalltalk etc. We will be learning C++ in this Self
Learning Material (SLM) to understand the object oriented programming.
ii) Classes
Class is a group of objects that have the same properties and common
behavior. A class is a category of things. An object is a specific item that
belongs to a class called ‘instance of class’.
A class defines the characteristics of its objects and the methods that can
be applied to its objects. Objects with the same data structure and behavior
are grouped together as class. Classes are templates that provide definition
to the objects of similar type. Objects are like variables created whenever
necessary in the program. For example, student may be a class and John,
James, Peter are objects of the class ‘student’. It is similar to the creation of
variables of a default datatype such as integer- you can create any number
of objects of a class.
iii) Inheritance
Inheritance is a technique through which one object acquires the properties
of another. The technique also supports hierarchical classification. It is a
powerful feature of OOP. It is a mechanism of deriving a new class from an
old class, and of inheriting all the characteristics and behaviours of the old
class.
The main advantage of Inheritance is "code reusability". The ability to reuse
components of a program is an important feature for any programming
language.
iv) Polymorphism
Polymorphism is the ability to present the same interface in different forms.
Polymorphism means “many forms of a single object”. Operator overloading
Manipal University Jaipur B2114 Page No.: 6
Object Oriented Programming – C++ Unit 1
1.5.2 Variables
Variable is a container of data i.e. Variables are names used to refer to
some memory location. Variables can be named according to the following
rules:
Variable name must begin with a letter.
Variable name contains letters, numbers and underscore.
Variable names are case sensitive.
Reserve words of C++ cannot be used
Declaration and definition of variables:
Variables have to be declared before being used in the program. Variable
declaration tells the compiler the name and datatype of the concerned
variable. General syntax of declaration of variable is
Datatype variablename;
Example: int p;
Here ‘const’ allows you to create constants. The value of data is fixed during
the entire program.
1.5.3.4 Operators
C++ has a rich set of operators. C++ supports all C operators. In C++,
operators are used to perform a specific operation on a set of operands in
an expression. Operators supported in C++ are listed below.
1. Arithmetic operators (+,-, *,/, %, ++,- -)
2. Relational operators (>,<, >=, <=, ==, !=)
3. Logical Operators (&&, ||, !)
4. Bit-wise operators (&, |. ^, ~ )
There are a few other operators supported by C++ language: sizeof, the
conditional operator and the cast operator. In later units, we will discuss in
detail these additional operators.
1.5.4 Operators: expressions
An expression is a sequence of operators and operands, used for
computation. Expression evaluation may produce a result (example:
evaluation of 2+2 produces the result 4).
i. Arithmetic operators: C++ provides five simple arithmetic operators for
creating arithmetic expressions. Table 1.3 below illustrates these arithmetic
operators with example. If the value of X=6 and Y=3, results for the
arithmetic operations are shown in Table 1.3.
Table 1.3: Arithmetic operators in C++
Documentation section
Header file section
Class declaration or definition section
Class function definition section
Main () function section
Figure 1.1: Basic Structure of C ++ program
11. The header file ___________ defines the cin, cout, and objects.
12. ______________ Statement is used for standard output or for output-
to- display screen.
13. Documentation section is optional, and is used to put ________ for the
program.
14. ___________ are used to group statements belonging to one function
or program statement.
During compilation, if there are any errors, they will be listed by the compiler.
The errors may be any one of the following:
1. Syntax error
Syntax error is an error in the structure or spelling of a statement. It
occurs when the program code breaks the basic syntax rules of C++
statement, as, for instance, in the wrong use of reserved words,
improper variable names, variables without declaration etc. Further
examples of syntax errors are- missing semi colon or parenthesis, type
integer for int datatype etc. Often, syntax error message indicates the
1.7 Summary
Let us recapitulate the important points discussed in this unit:
Computer performs a variety of tasks with the help of programming
languages. In 1980, Bjarne Stroustrup, from Bell labs, began the
development of the C++ language.
C++ is a superset of C. Several features are similar in C and C++.
Object-oriented Programming (OOP) is considered as important as the
development of high level languages. The basic features of OOP
language are: Objects, Classes, Inheritance. Polymorphism,
Encapsulation.
Object-oriented Programming enables storing of data and functions
together, which in turn enables hiding of data from unnecessary
exposure.
A class defines the characteristics of its objects and the methods that
can be applied to its objects. The main advantage of Inheritance is
"code reusability".
C++ language supports following data types: char, int, float, double. A
programmer uses C++ tokens to write a program.
C++ supports the following types of tokens: identifiers, keywords,
constants and operators. An expression is a sequence of operators and
operands, used for computation.
The header file “iostream.h” defines the cin, cout, objects, which
correspond to the standard input stream and the standard output stream
respectively.
To write and execute C++ programs, you need to have a text editor and
C++ compiler. In market various types of compilers are available: GNU
C++, Borland C++, Zortech C++, NDP C++, etc.
1.9 Answers
Self Assessment Questions
1. Bjarne Stroustrup
2. mnemonics
3. integer
4. class
5. Inheritance
6. data hiding
7. Message passing
8. False
9. reserve words
10. Logical operators
11. iostream.h
12. cout
13. comments
14. Parenthesis
15. Compiling
16. Syntax error
17. execution
18. compile
19. .obj
Terminal Questions
1. a. Encapsulation: Encapsulation used to bind code and data together.
Wrapping of data and methods into a single unit is called
‘encapsulation’.
b. Inheritance: Inheritance is a technique by which one object acquires
the properties of another object. The technique also supports a
hierarchical classification.
int num1,num2;
cout <<” enter two numbers”;
cin>> num1>>num2;
Num1=num1+num2;
Num2=num1-num2;
Num1=num1-num2;
cout<< “numbers after swapping are ”<<num1<<num2;
}
7. Program to divide a and b and display quotient and remainder
# include<iostream.h>
void main()
{ int a,b, q, rem;
cout <<” enter two numbers”;
cin>> a>>b;
q=a/b;
r =a%b;
cout<< “Quotient = ”<<q<<endl;
cout<<”remainder=”<<r;
}
References:
Object-Oriented Programming Using C++, By B. Chandra, CRC Press.
Starting Out with C++: From Control Structures Through Objects, Global
Edition, by Tony Gaddis, Pearson Education.
2.1 Introduction
In the previous unit, you studied about the basic concepts of object- oriented
programming, the important components of programing language and the
process of compilation and execution of a program. Programs are usually
executed sequentially. In this unit, we will discuss the execution of programs
based on control and iterative statement. Control statements execute
program statements sequentially, based on certain conditions. Iteration
statements cause block of statements to execute repeatedly. In this unit, we
will also discuss arrays, multi-dimensional arrays and pointers.
Objectives:
After studying this unit, you should be able to:
describe the conditional and unconditional statements
discuss iteration statements
define an array and explain how to declare different types of arrays
explain the use of multidimensional arrays
create a pointer and initialize values to the pointer
Syntax:
if (expression or condition)
{
Statement (s)
}
else
{
Statement (s);
}
The example program given below accepts a number from the user, and
displays whether given number is even or odd number.
# include <iostream. h>
void main(){
int x;
cout <<"enter the value of x\n'\";
cin>>x;
if(x%2 == 0)
cout <<" print even number";
else
cout<< " print odd number";
getch();
}
Nested-If statement
If-else statement is useful only if condition has to satisfy two possible
alternatives. If there is a need to check multiple alternatives, then use a
nested-if statement, i.e. an “if statement” in an “if statement” (one if
statement having another if statement, and so on is known as ‘nesting’). The
syntax of nested-if statement is specified as:
Syntax:
if (condition1)
{
if (condition 2)
{
Statement1;
Statement2;
}
else if (condition3)
{
Statement3;
}
else
Statement 4 ;
}
Next statements after if statement;
The flowchart for the nested-if statement is shown in figure 2.1.
The above program number reads student marks, and displays the grade
obtained by the student. Here nested-if conditions are used to check the
grade of a student. Once the condition is true, it displays corresponding
message, i.e. the grade of the student.
Switch statement
If you are using more if- else statements i.e. nested-if statements in a
program, then it looks a bit confusing. One alternative to nested-if is the
switch statement. Switch statement helps you to check the different values
of the same variable and execute the statements accordingly. The syntax of
the switch statement is given below:
Syntax:
switch (variablename)
{
case constant1: statement1;
break;
case constant2: statement2;
break;
case constant3: statement3;
break;
default: statement4;
}
If the variable in the switch statement is equal to constant1 then statement1
is executed, but if it is equal to constant2 then statement 2 is executed. If it
is constant 3, then statement 3 is executed. If the variable value is not in
any of the cases listed, then the default case statement i.e. statement 4 is
executed. The default case specification is optional; however, keeping it is a
good practice.
Every case should have a break statement as the last statement. Break
statement takes the control out of the switch statement. Absence of the
break statement can cause execution of statements in the next case. No
break is necessary for the last case. In the above syntax, the default case
does not contain a break statement.
In the above program, the user reads two variables, i.e. i=1 and total=0. To
find the sum of numbers, add i value to the total and increment the ‘i’ value
by 1(represented with i++). Here, inside an if loop one more if loop is used.
The first if loop checks whether the ‘i' is less than 10 or not. The second if
loop verifies the condition whether i is equal to 5 or not. When i value
becomes 5, then it executes the break statement that will terminate the loop,
and then the control passes out of the if block.
Continue statement is used to take the control to the next iteration of the
loop. It is used if the control has to be transferred to the next iteration of the
loop based on a condition, skipping all the other statements in the loop. The
following program shows the use of a continue statement.
Example
# include<iostream.h>
void main()
{
int i=1, n;
cout< “enter the number” ;
cin>>n;
if(i<=n)
{
i++;
if(i%2==0)
cout<< i<<"\is even number \n";
else
continue;
}
}
The above program enables you to use a continue statement. A Program
reads the value of variable n and displays even number values up to n.
There are two if conditions in a program: the first if condition checks whether
i value is less than or equal to n, and the second if condition checks whether
i value is an even number or not. If i value is even, it displays that value, or
else the control of execution is passed to the continue statement. Here the
continue statement, first of all, passes the control to if condition and helps to
repeat the loop up to i value equal to n. Once i value becomes greater than
n, then the first if condition becomes false, and the control is passed out of
loop.
Exit
Sometimes you need to end your program (or a sub section of a program)
earlier than the normal termination. C++ supports exit statement to exit
programs and returns an exit code. Exit is an inbuilt library function. To use
exit program the header file process.h has to be included in the program.
The syntax of an exit program is specified as :
Exit (integer)
Here the integer value return to operating system (OS) while terminating
program.
Exit (0) means - no error i.e. successful termination.
Exit (nonzero value) means– error while exiting the program.
#include<iostream>
#include<process.h>
int main()
{
cout<" example program for exit';
Exit(0); // this statement terminates the program and returns 0 to OS
cout <<' this statement will never executed";
}
The example shown above shows termination of the program before
reaching the end of the program. Exit code 0 indicates a normal program
termination.
Self Assessment Questions
1. Conditional operator is an alternative to __________ statement.
2. Each case in switch statement should end with _________ statement.
3. __________ statement is used to take the control to the next iteration
of the loop.
4. __________ header file should be included to use exit function.
5. __________ Statement takes the control to the beginning of the loop.
while ( i <= n) {
factorial = factorial* i;
i++;
}
cout<<"Factorial of "<<n<<" = "<<factorial;
}
The program number accepts positive integer number n from the user and
finds the factorial of that number. In the program shown above, the variables
i and factorial are initialized to one. The variable i is incremented every time
while loop becomes true. Calculate factorial value by multiplying i value with
the factorial variable. Once i value becomes greater than n, while condition
becomes false, and the control passes out of the loop and displays output
i.e. factorial of a given number.
Do... while loop
Do-while is similar to while loop, except that a do--while loop body
statement executes at least once before the condition is tested.
When the condition is true, the control statement jumps back to do
statement, and the body of statements in loop executes again. This process
repeats until condition becomes false.
In do-while loop, the condition is checked at the end of loop and so it is
called exit-control statement, whereas while loop is called entry -control
statement.
Syntax:
do
{
// do-while loop body of statements
Statement1;
Statement2
} while (condition expression);
Next statements after do-while condition;
In the syntax given above, statement1 and statement2 are executed, and
the condition is checked. In other words, the do-while loop body statement
executes before the condition. If the condition is true, then the statements
are executed again, and if the condition is false, then the control is
transferred to the next statement after the do-while statement.
The flowchart for the do... while statement is shown in Figure 2.4.
Please note that there is no semicolon after do, but there is a semicolon
after the condition expression in while part.
The following program implements the do-while loop
#include<iostream.h>
int main() {
int n, i = 1, factorial = 1;
cout<< "Enter a positive integer: ";
cin >> n;
do{
factorial = factorial* i;
i++;
} while ( i <= n);
cout<<"Factorial of "<<n<<" = "<<factorial;
}
The decision on whether to use while or do.. while statement depends on
whether the statements inside the loop have to be executed atleast once or
not. If it has to be executed atleast once, then the do.. while statement
should be used.
For loop
The for loops are the most useful type of loops. The syntax of the for loop is
shown below. The loop condition contains three parts. They are: loop
initialization, loop termination condition and statement for the next iteration,
and these three parts are separated with semi-colons.
Syntax:
for(initialization statement; loop termination condition; statement to
increment/decrement the loop variable)
{
//body of for loop;
Statement1;
Statement2;
}
In the example given above, initiation statement is executed first, and then
the termination is checked. If the condition is true, body of the for loop is
executed i.e. statement1 and statement2 are executed. Then the third
statement in for loop is executed, which modifies the loop control variable.
The flowchart for the statement is shown in Figure 2.5.
The following program implements the factorial of a number using for loop
#include<iostream.h>
int main() {
int n, i , factorial = 1;
cout<< "Enter a positive integer: ";
cin >> n;
}
cout<<"Factorial of "<<n<<" = "<<factorial;
}
The for statement can also have multiple initialization and decrement and
increment statements as shown in the following expression
for(i=0,j=0;i<=n;j++,i++)
{
Statements;
}
Please note that in the case of multiple statements, each statement should
be separated by a comma.
Selection of the various types of loop to be used in the program depends on
the programmer style. However, you should use for loop if you know in
advance how many times the loop has to be executed. If the loop has to be
executed at-least once, irrespective of whether the condition is true or false,
then do-while loop should be used.
Self Assessment Questions
6. Which of the following is true for do-while loop?
a. Entry control statement
b. Exit control statement
c. Temporary statement
d. Conditional operator statement
7. Do-while loop will be executed at least once, even if the condition is
____________.
8. The for statement can also have multiple initialization, and decrement
and increment statements. (True/ False)
element of the array can be accessed separately in any order. The size of
the array matches with the number of values it contains.
2.4.1 Declaration and definition of arrays
Like variable declaration, arrays are also declared along with the data type.
Array declaration reserves space for a number of elements. The declaration
of array contains the name of the array along with square brackets. Inside
the square brackets specify size of the array.
Int x[10];
An integer array x is declared with the size 10. The size is used to indicate
the number of elements an array can store. The elements of an array can
be accessed using the array name followed by index number within square
brackets, i.e. x[0], x[1] to till x[9]. The index of an array starts with 0 and the
last index number of an array is size-1.
2.4.2 Initialization of array
To specify values to an array, we should explicitly initialize specific values.
You can specify declaration and initialization of the array in a single
statement. Initialization of an array can be defined in the following form:
int a[5]= { 3, 6, 9,12,15}
The number of values between braces { } are not more than the size of the
array. Declaration and initialization of the array can be done in a single
statement. Then the above example can also be declared and initialized as
follows:
Int a[]= { 3, 6, 9,12,15}
Supposing you declare the array and initialize values to it using the same
statement, you can omit the size of the array.
The following program shows how you can add values of array to find the
sum of elements of the array.
#include<iostream.h>
void main()
{
int i, sum = 0;
int a[10] = {1, 2, 3,4,6,9,2,8,5,10}; // array with size 10
{
sum = sum + a[i];
}
Another interesting aspect of the array is that all the elements in the arrays
are allotted consecutive spaces in the memory by the operating system.
The following program sorts an array. Here nested for loops are used to
enable this.
# include<iostream.h>
void main()
{
int a[10],temp;
for (int i=0; i<10;i++)
{
cin>>a[i];
}
cout<<"Array after sorting is ";
for(int j=0; j<9;j++)
for(i=0;i<9;i++)
{ if (a[i]>a[i+1])
{temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
}
for (i=0; i<10;i++)
{
cout<<a[i]<<endl;
Manipal University Jaipur B2114 Page No.: 41
Object Oriented Programming – C++ Unit 2
}
}
All the elements in the array should be initialized. Every data should be
separated by a comma and all the elements enclosed within flower brackets
are as shown below:
int data[5] = {3,5,7,4,9};
In the above initialization, data[0] is initialized to 3, and data[1] is initialized
to 5 and so on..
3 data[0]
5 data[1]
7 data[2]
4 data[3]
9 data[4]
a matrix. A 3x4 matrix that has 12 data elements can be created using the
following declaration
int A[3][4];
The array A[3][4] has three rows and four columns. The elements in the
array can be accessed by two indices. To refer to an element in the first row
and second column, A[0][1] has to be used since the index starts from zero.
The following program accepts two, 2x3 matrices from the user and adds
the two matrices.
//matrix.cpp
# include <iostream.h>
void main()
{
int a[2][3], b[2][3], c[2][3];
int i,j;
cout<<”Enter the elements for the first 2x3 matrix”;
for (i=0;i<2;i++)
for (j=0;j<3;j++)
{ cin>>a[i][j];}
cout<<”Enter the elements for the second 2x3 matrix”;
for (i=0;i<2;i++)
for (j=0;j<3;j++)
{
cin>>b[i][j];
c[i][j]=a[i][j]+b[i][j];
}
cout<<”The resultant matrix is”;
for ( i=0;i<2;i++)
{
for ( j=0;j<3;j++)
{
cout<<c[i][j]<<” “;
}
cout<< endl;
}
}
2.6 Pointers
Pointers are a very powerful feature of the language with many uses in
programming. Pointer is a variable that stores the address of another
variable.
Some of the programing tasks are performed more easily with pointers such
as dynamic memory allocation (i.e. obtaining memory at runtime from the
system).
As you know, every variable created in a program is stored in the memory.
The location of memory in a system can be accessed through the address.
The address of a variable can be accessed using ampersand (&) operator.
If there is an integer variable named P in the program, and if you have
statement cout<<&P, the program will display the address of the variable P,
which will be a hexadecimal number.
int * A;
int B [10];
As we have already studied with regard to the array, brackets ([]) are used
to specify the size of an array. We can assign pointer variable to an array.
So, the following assignment statement is valid.
A = B;
Pointers and arrays support the same set of operations, with the same
meaning for both. The main difference is that the pointers can be assigned
new addresses, while the arrays cannot.
Following example illustrates the use of pointers and arrays
# include< iostream.h>
void main ()
{
int A[5];
int * p;
p = A; *p = 10;
p++; *p = 20; p = &A[1];
p++; *p = 30; p = &A[2];
for (int n=0; n<3; n++)
cout << A[n] << ", ";
}
In the program given above, the statement p=A assigns values of an array
to a pointer.
When Pointer p increments, address of pointer will move to the next
address location. Here value of the array is assigned to the pointer. Using
for loop, the program displays array values.
If we know the size of an array, we can easily assign values to the array
using index without wastage of memory. When there is no idea about the
size of an array in advance, array can be declared using pointer.
Pointer uses “New” operator to allocate memory to array during runtime and
returns the memory location of the first element in the array. Using new
operator, we can create (allocate) and delete (destroy) the objects
dynamically.
The syntax of the new operator is:
Pointervariable = new data type [size];
where data type can be any basic or user-defined and the size is any
integer value.
Delete operator is used to return the memory to the system. The syntax of
delete operator is:
delete pointervariable;
where pointervariable is the pointer containing address returned by the
system.
The following program creates a dynamic array, and finds the sum of array
elements:
#include<iostream.h>
void main()
{
int n, sum=0;
int* ptr;
cout<<"enter the size of the array"<<endl;
cin>>n;
ptr=new int[n];
cout<<"enter"<<n<<"numbers";
for(int i=0;i<n;i++)
{cin>>ptr[i];
sum=sum+ ptr[i];}
}
cout<<"sum ="<<sum;
delete ptr;
getch();
}
In the program given above, the statement ptr=new int[n]; asks the system
to allocate memory of size n. It store integer values and stores the address
of the memory allotted in the pointer variable ptr.
Self Assessment questions
17. Pointers are variables that store ____________.
18. ____________ Operator can be used to request memory from the
system during runtime.
2.7 Summary
Let us recapitulate the important points discussed in this unit.
This unit discusses the various conditional control statements and
iteration statements, arrays and pointers that are supported by C++.
If statement and switch statement are the conditional control statements
that are executed based on given condition.
In the switch statement, the break statement is used in every case
statement to terminate the switch statement and to pass the control out
of the switch block.
Continue statement is used to take the control to the next iteration of the
loop.
Iteration statements used to execute the block of statements for
repeated number of times. There are three types of iterative statements:
while, do while and for.
Arrays are used to store large volumes of similar data together. The
array elements can be accessed by specifying array name followed by
the number which indicates the position of the element in the array.
Arrays of basic datatypes such as integers, characters etc., and user-
defined datatypes such as structures, objects can be defined. Arrays
can be multidimensional, helping to store data that are related.
Pointers are a very powerful feature of the language that has many uses
in programming. Pointers are variables that store address values of
other variables. They are defined by prefixing an * to the variable name.
Pointer can be used with arrays. Both are related to each other. Pointer
uses “New” operator to allocate memory to array during runtime, and
returns the array of the memory location of the first element in the array.
5. Write a program that accepts a 3x3 matrix from the user and finds the
transpose of it.
6. Explain the pointer operator “New” with an example program.
2.9 Answers
Self Assessment Questions
1. if –else statement
2. Break statement
3. Continue
4. process.h
5. break
6. B. Exit control statement
7. False
8. True
9. same
10. ten
11. sixth
12. array name followed by index number in square brackets
13. True
14. 20
15. a[2][3]
16. False
17. address values of other variables
18. New
Terminal Questions
1. If-else: Another type of if statement is if-else statement. If the condition
is true, then it executes ‘if block’ statements. If the condition is false,
then it executes ‘else block’ statements.
Conditional operator: Conditional operator is also called ‘ternary
operator’. Conditional operator works similar to if-else statements. For
more details, refer section 2.2.1.
2. In do-while loop the condition is checked at the end of the loop. So it is
called an ‘exit-control’ statement, whereas while loop is called ‘entry-
control’ statement. For more details refer section 2.3
{
cin>>a[i][j];
at[j][i]=a[i][j];
}
cout<<”The transpose is”;
for ( i=0;i<3;i++)
{
for ( j=0;j<3;j++)
{
cout<<at[i][j]<<” “;
}
cout<< endl;
}
}
6. A Pointer uses the “New” operator to allocate memory to the array
during runtime, and returns the array of the memory location of the first
element in the array. For more details refer section 2.6.1.
References:
Learning C++ Programming Concepts by Tickoo Sham, Pearson
Education India.
C++ for Programmers by Paul Deitel, Harvey M. Deitel, Pearson
Education.
C++ Primer Plus by Stephen Prata, Addison-Wesley Professional.
Object-oriented Programming with C++ - Sixth Edition by
E. Balagurusamy. Tata McGraw-Hill Education.
3.1 Introduction
In previous unit, you have studied execution flow of programs based on
certain conditions/statements. You have also studied how to store collection
of values in single variable using array. In this unit, we will discuss the reuse
of code using function, how to declare and define a function. We will also
discuss scope and visibility of variables, use of storage classes, declaration
of strings and how to initialize values to strings. Finally we will discuss user
defined data types, structures and unions.
Objectives:
After studying this unit you should be able to:
explain functions and how they enable program organization
discuss different types of variables based on scope
define strings and explain its uses
describe different types of string library functions
define structure and union
differentiate between structures and unions
If function has more than one parameter they should be separated with a
comma.
A function that accepts data from other functions does so by accepting one
or more parameters from the sending function. Information that is passed to
a function is called arguments to the function or simple arguments.
Definition of function
A function definition provides the actual body of the function. A c++ function
definition consists of a function header and function body. Function header
is similar to prototype of function. Function header specifies return type of
function, function name and parameter list. The only difference between the
header and the prototype is the semicolon. If you specify semicolon at the
end of function heading, it generates a syntax error. Function body is group
of statements or syntactical statement. Function needs to be declared
before it is used, but can be defined anywhere in the program or linked file.
The idea of declaring a function before defining it is called forward
declaration. If you define a function before calling it, you do not necessarily
need a definition.
The general syntax of function definition is:
return-type function_name (parameter list) // function header
{
Statements; //Function body
}
The arguments should match during function call with respect to data type
and order of the arguments. In case of default arguments, the value need
not be specified during call.
Let us discuss an example of declaration of a function named square which
inputs a number and returns the square of the number.
int square(int);
Please note that all the arguments are enclosed within brackets. If there are
no arguments, void should be specified within the brackets. The following is
the declaration of a function which does not have return value and does not
have any arguments.
void xyz(void);
int a,b ;
cout<< “enter two numbers”;
cin>>a>>b;
swap(a,b);
cout<<”The value of a is”<<a<<endl;
cout<<”The value of b is”<<b<<endl;
}
void swap(int& m, int& n)
{ int temp;
temp=m;
m=n;
n=temp;
}
In the above program, the variables a and b are passed by reference which
implies that they will be accessed directly. However, the variables will be
referred as m and n in the function and are swapped. The result is that the
function swaps the values in the original variables a and b.
You can also have more than one user defined functions that can have
same name and perform different operations. This is a powerful feature of
C++ and is known as function overloading. Every overloaded function
should however have a different prototype. The following example
(printoverload.cpp) program implements an overloaded function print line ()
# include <iostream.h>
void printline();
void printline(char ch);
void printline(char ch, int n);
void main()
{
printline();
printline(“*”);
printline(“*”, 20);
}
void printline();
{ for(int i=0;i<25;i++)
cout<<”-“;
cout<<endl;
Manipal University Jaipur B2114 Page No.: 58
Object Oriented Programming – C++ Unit 3
}
void printline(char ch);
{for (int i=0;i<25;i++)
cout<<ch;
cout<<endl;
}
void printline(char ch, int n);
{ for (int i=0;i<n;i++)
cout<<ch;
cout<<endl;
}
In the above program, the function printline has three different prototypes
depending on the arguments passed to it. The relevant function is invoked
depending on the type and number of arguments passed to it.
Functions can also contain default arguments. Default arguments are
those whose values need not be explicitly passed during function call.
However, the default arguments should be specified in the end of the
argument list to avoid ambiguity arising during function overloading. The
default values are specified while declaring the function along with the data
type of the argument. The variable name may or may not be specified
during declaration.
The prgram (printoverload.cpp) can also be implemented through default
arguments as shown below example (default.cpp).
//defaultarg.cpp
# include <iostream.h>
void printline(char ch=”*”, int n=25);
void main()
{
printline();
printline(“-”);
printline(“-”, 20);
}
void printline(char ch=”*”, int n=25);
{ for(int i=0;i<n;i++)
cout<<ch;
cout<<endl;
}
In the example 3.4, variable ch and n values are declared as value of
variable n is 25 and value of ch is *. However, if the values are specified
explicitly, then the default values will not be considered.
Arrays can be used as arguments to functions. It is similar to pass any other
variables as shown in the example program (matrix.cpp) below:
//matrix.cpp
# include<iostream.h>
void display(int arr[3][4]);
void main()
{ int matrix1[3][4], matrix2[3][4], sum[3][4];
int i,j;
cout<<”Enter the elements of matrix one”;
for(i=0; i<3;i++)
for(j=0:j<4;j++)
cin>>matrix1[i][j];
cout<<”Enter the elements of matrix two”;
for(i=0; i<3;i++)
for(j=0:j<4;j++)
{
cin>>matrix2[i][j];
sum=matrix1[i][j]+ matrix2[i][j];
}
cout<<”sum is”;
display(sum);
}
void display(int arr[3][4] )
{
for(int i=0;i<3;i++)
{for(int j=0;j<3;j++)
cout<<arr[i][j]<<” “;
cout<<endl;}
}
}
void f1(int x)
{ static int sum, n;
sum=sum+x;
n=n+1;
avg=sum/n;
cout<< “Average is”<<avg;
}
The above program allows the user to enter any number of integers and
computes the average of the numbers. The static variables sum and n are
initialized to zero. They are updated when user enters a new number and
the function is called. The values of these variables are retained even after
the function returns to the main program.
The summary of all three storage classes is shown below:
Automatic Static External
Visibility Function Function Program
Lifetime Function Program Program
Initialized Junk value in Zero Zero
to memory
Purpose Variables used Same as automatic but the Variables used
by single value should be retained by several
function when function terminates functions
3.5 Strings
C++ implements strings as character array. We know that C language does
not support a built in string type. We have to use character arrays to store
and manipulate strings. One problem with character array is that memory
crashes due to insufficient declaration. To avoid that problem C++ provides
a new class called string. The string object may be used like any other
built-in data type. C++ provides a data type "string", by using string data
type we can declare and initialize string values easily.
Strings are used to store character names like name, address, password etc.
Stings are similar to arrays. Like array, string sizes are also defined during
declaration statement. Main difference between string and array is that
every string in c++ must be terminated by null character (’/0’) to mark end of
the string. Strings, unlike other arrays can be input without using a loop.
When inputting strings using cin statement, the compiler stops taking input
from the user once it encounters space or linefeed (pressing enter key).
3.5.1 Declaration and initialization of strings
The string variable declaration and initialization can be done by using single
statement. The strings can also be initialized as arrays.
The following example declares an array of 6 elements of type char
initialized with the characters that form the word "hello" plus a null character
'\0' at the end. It is specified by enclosing the text (hello) between double
quotes.
char str[6]= “hello”;
Strings can also be defined without specifying the size, but in that case they
have to be initialized to a string constant as shown in the following example.
char str[]=”hello world”
However, there is no built in mechanism in C++ that disallows the user to
enter characters than the string maximum size. The extra characters
entered by the user will be truncated. To keep a check on the number of
characters, setw () function can also be used. To use this function,
iomanip.h header file should be included. Let us see one example of it in the
following program (stringexample.cpp).
#include<iostream.h>
#include<iomanip.h>
const int size=10;
void main()
{
char str[size];
cout<<”enter a string”;
cin>>setw(size)>>str;
}
In the program shown above, the user can enter only nine characters
because last one character stores null character (’/0’). While the strings are
input, cin stops reading once it encounters space or linefeed character
(when user presses enter). To read the text containing blank space and to
read multiple lines of text cin.get function can be used. The following
statement will allow the user to input a maximum of 39 characters which can
even include blanks. It will stop reading once it encounters linefeed
character.
cin.get(str, 40);
To read multiple line of text from the user, you have to specify a terminating
character which will be used to recognize end of input. In the following
example, the terminating character is $.
cin.get(str,40,$);
The above example will allow users to enter a maximum of 39 characters
which can include embedded blanks and linefeed.
3.5.2 Standard C++ String functions
C++ standard library provides several string functions used to manipulate
strings. All string library functions are defined in the header file string.h.
Whenever you use string standard function, the header file “strig.h” has to
be included. The table 3.1 lists some of commonly used string functions
Table 3.1: String library functions
String Library
Meaning
function
strlen() Used to find the length of string
strrev() Used to arrange the characters in the string variable in
reverse order except for the null character.
strcpy Used to copy the contents of one string to another.
strcmp Used to compare two strings.
Strlen Function
This function is used to find the length of the string. The general syntax is:
strlen(string variable)
strlen(n) function returns the number of characters or length of the string n.
In the statement shown above, the string constant OOPS is assigned to the
string variable name q. The assignment of a string variable cannot be done
using an assignment operator. It should be done using strcpy function.
Strcmp function
Strcmp function is used to compare two strings. The syntax of strcmp is :
strcmp(string1,string2)
Every character of string1 will be compared with the corresponding
character of string2. The ASCII values of the character will be used to
decide the return value. The function returns an integer and the value
returned will differ based on the conditions as shown below:
If string1 < string2, value returned will be <0
If string1==string2, value returned will be 0
If string1> string2, value returned will be greater than zero.
Thus, a return value 0 implies that strings are equal and a non-zero return
value implies that the two strings are not equal. Please note that the above
function is case sensitive. strcmpi () function can be used if the two strings
have to be compared without case sensitiveness.
The following program (stcmpexample.cpp) implements strcmp function
// stcmpexample.cpp
#include <iostream.h>
#include <string.h>
void main ()
{
char str1[30], str2[30];
for(int i=0;i<10;i++)
{
cout<<"Enter first string: ";
cin>>str1;
}
for(int i=0;i<10;i++)
{
cout<<"Enter first string: ";
cin>>str2;
}
if(strcmp(str1,str2)==0)
cout<<"Both strings are equal";
else
cout<<"Strings are unequal";
return 0;
}
Self Assessment Questions
12. The string variable declaration and initialization can be done by using
single statement. (True/False)
13. _____________ Function is used to copy the contents of one string to
another.
14. To read blanks between the strings or to read multiple lines of text,
_________ function which is a member function of cin can be used
int deptcode;
float salary;
};
Structure is a feature in C++ that enables you to define a user-defined
datatype. Once you specify the definition of the structure, you can create
variables of that structure. In the above definition, we have defined a
structure using the keyword struct followed by the name of the structure
(employee). All the data items that need to be defined are defined by
specifying the datatype and name of the variable. Once the definition is
done, variables of type employee can be created. For example, the
following statement creates a variable e1 of type employee.
employee e1;
Structure variables can be initialized during declaration. The values for all
the members should be specified separated by comma and all the values
enclosed within flower brackets as shown below
employee e1= {1234, “Ajay”, 12, 6900.00};
Structure variables can be copied and assigned to another structure
variable as shown below
employee e2;
e2=e1;
To access the members of the structure variables, dot operators can be
used. For example to access empid of structure variable e1, you would say
e1.empid (structure variable. member variable name).
Structures can be nested within each other. When accessing the members
and sub members dot operators can be used. Let us suppose you have
defined a structure named distance with two members’ length and width as
declared below:
struct distance
{ int feet;
int inches;
}
Let us now define a structure named room, which contains variables of type
distance:
struct room
{ distance length;
distance width;
distance height;
} bedroom;
In the definition of room given above, we have declared a variable bedroom
of type room along with the definition. To access the members of the
bedroom you can use:
bedroom.length.feet
bedroom.length.inches
bedroom.width.feet
bedroom.width.inches and so on
To initialize nested structures you have to group together all the elements of
the structure:
room dining = {{12, 3},{13,0},{11,2}}
In the declaration of room dining, the values 12 and 3 refer to
dining.length.feet and dining.length.inches respectively. Similarly, the
second and third set of values represent feet and inches of width and height
respectively.
You can also create array of structures. For this, the index number should
be specified immediately after the structure variable. For example, the
statement
employee emp[50] ;
will create an array of structure employee.
To access the first array member, you can say emp[0].empid
The below program (structexample.cpp) implements a structure point with
x and y co-ordinates.
//structexample.cpp#include<iostream.h>
#include<conio.h>
# include<math.h>
struct point
{ int x,y;
} p1,p2;
void main()
{
int s;
cout<< “Enter the co-ordinates for first co-ordinate” ;
cin>> p1.x>>p1.y;
cout<<”enter the co-ordinates for second co-ordinate”;
cin>>p2.x>>p2.y;
s=sqrt(((p2.y-p1.y)*(p2.y-p1.y))+((p2.x-p1.x)*(p2.x-p1.x))) ;
cout<<endl<<”the distance between the two points is”<<s;
getch();
}
In the program shown above, we have defined a structure point which
stores x and y co-ordinates of the point. Along with the declaration, we have
also created two point variables p1 and p2. This is a way to create variables
along with the structure declaration. This can be a separate statement also
as discussed earlier. The program accepts two points from the user and
displays the distance between them.
Structures are good mechanism of creating user defined datatypes. C++
specifies another method known as enumerated data type to enable users
create their own datatypes. Enumerated data types can store fixed set of
values and you can perform arithmetic on them as well. They are defined
using the keyword enum. The program shown below (enumerated.cpp)
creates an enumerated datatype that stores different days of the week.
//enumerated.cpp
#include <iostream.h>
enum weekday {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
void main ( )
{
weekday day1,day2;
day1=Mon;
day2= Fri;
int diff=day2-day1;
cout<<”days between =”<<diff;
if (day1<day2)
Manipal University Jaipur B2114 Page No.: 73
Object Oriented Programming – C++ Unit 3
3.7 Summary
Let us recapitulate the important points of this unit:
Functions provide good mechanism to organize data. Functions are
given a name which can be used to call the function and execute the
statements in the functions.
Functions can also take inputs which are known as arguments which
passed during function call.
Arguments can be passed either by value or by reference. They can
also have return value which can return a computed value back to the
main program.
Inline functions enable programmers to save processing time by
reducing the overheads involved in function call.
Programs can make use of automatic, external and static variables
which have different types of utility depending on the way the variable
should be accessed and whether the value has to be retained.
Strings are nothing but character arrays. C++ standard library provides
several string functions used to manipulate strings.
Structures and unions data types enable users to create user defined
data types. Structure, is a group data item which has heterogeneous
collection of data.
Enumerated data types create data types that can store pre-defined and
fixed set of values.
Union is a special class type that can hold only one of its non-static data
members at a time.
Union declaration is similar to structure declaration as it allows us to
group together dissimilar type elements inside a single unit.
3. What is a string? Explain with example how string can be declared and
initialized.
4. Differentiate between structures and unions.
5. Define a structure named product with elements productcode,
description, unitprice and qtyinhand. Write a C++ program that
implements the structure and enables to store at least 100 product data.
6. Write a function that takes input as radius of the circle from keyboard
and return the area of the circle.
7. Write a function that takes two integers, finds out which is smaller and
then assigns zero to the smaller variable and returns the value.
3.9 Answers
Self Assessment Questions
1. function prototype
2. function signature
3. return
4. True
5. pass by value
6. returning multiple values and modifying original values
7. Function overloading
8. declaration
9. execution time
10. zero
11. Program file
12. True
13. Strcpy
14. get
15. False
16. struct
17. dot operator (structure variable name.member name)
Terminal Questions
1. One method of passing data to function is passing by value. In this way
of passing variables, a copy of the variable (main program) is created
during function call with the name specified in the function and initialized
with the value in the original variable.
cout<<p[i].qtyinhand;
}
}
6. //areacircle.cpp
# include <iostream.h>
int carea(int radius); // function declaration
void main()
{
int radius ;
cout<< “enter radius”;
cin>>radius;
cout<<“The area of circle is”<<carea(radius)<<endl;
}
int carea(int radius) //function defintion
{ int a;
a= 3.14*radius*radius;
return a;
}
7. //smallzero.cpp
# include <iostream.h>
void smallzero (int& m, int& n); // function declaration
void main()
{
int a,b ;
cout<< “enter two numbers”;
cin>>a>>b;
smallzero(a,b);
cout<<“The value of a is”<<a<<endl;
cout<<“The value of b is”<<b<<endl;
}
void smallzero(int& m, int& n) //function definition
{ if (m<n)
m=0;
else if (m>n)
n=0
else
{
m=0;
n=0;
}
}
References:
An Introduction to Object-Oriented Programming in C++, 2nd edition,
By Graham M. Seed, Springer Science & Business Media.
Object Oriented Programming with C++ - Sixth Edition,
by E Balagurusamy. Tata McGraw-Hill Education.
Object-Oriented Systems in C++, by Dr. Durgesh Pant, Mahesh Kumar
Sharma, K.S. Vaisla, Firewall Media.
4.1 Introduction
In the previous unit, you have studied how to reuse code using function.
You have also studied storage classes, strings (array of characters),
structures and unions. Structures and unions are used to group
heterogeneous data.
In this unit, we will discuss implementation of objects and classes. In real life
we come across the situations where we have to model the functionality of
data type along with data. Classes bind data and functions that act on data
together. However, in C++ structures are used in the same way as classes
by binding together functions and data. But you should use structures only
in situations when it is required to group together the data and the functions.
In C++ there are objects which are the instances of class. The objects have
a similar relationship with classes as variables have with data types. Object
is an instance of a class.
In this unit, we will also discuss important features of C++, such as, access
specifiers, abstract classes, this pointer, friend functions, and static
functions.
Objectives:
After studying this unit you should be able to:
explain the role of class and objects in oops
define different types of access specifiers
describe this pointer
discuss friend function, its advantages, and scope
discuss static variables and static functions.
}
Real world entities such as, employee, vehicle, animal, etc. can be modelled
by class or it can model a user defined data type such as string, distance,
etc.
Example:
class Student
{
int rollnumber;
string name;
float grade;
};
Let see one more simple example of class
class product
{
int product_id; // data varibles declartion
double cost;
void getdat(int a, float b); // member function decalrtion
void putdat(void);
}
In the above example the class product contains two data variables and two
member functions.
Self Assessment Questions
1. A ________ is an abstraction of the real world entities with similar
properties.
2. A class is an implementation of _____________ datatype.
{ distance d1;
d1. setdistance(10, 2);
d1.printdistance();
}
In the above program, there is a class distance with two data members- feet
and inches and two member functions or methods; setdistance() and
printdistance(). You can define a class with the keyword class followed by
the name of the class. As you can see in the main program, d1 is an object
of class distance. Every object of a class has its own copy of data, but all
the objects of a class share the functions. There is no separate copy of the
member function for every object of class. The data can be accessed by the
objects through member functions or methods. To invoke the member
functions of class we have to use object of that class. The member functions
cannot be invoked without the objects of the class. The methods defined in
the class can only be invoked by the objects of the class. Without an object,
methods of the function cannot be invoked.
Self Assessment Questions
3. An instance of a class is known as an ______ of that class and is used
in the program to store data.
4. The object is created by using the class name followed by object name.
(True/False)
of type class and those variable are called arrays of objects. Let us consider
the following definition of class:
class distance
{
Private:
int feet;
float inches;
public:
void getdist();
void printdist();
};
The identifier distance is a name of the class which is a user defined
datatype and can be used to create objects of type distance.
Example:
distance D[2] // array of two distances
distance dist[5] //array of five distances
The array D contains two objects namely D[0] and D[1]. The array dist
contains five objects namely dist[0], dist[1], dist[2], dist[3].
To access the member functions you can use the usual array accessing
method followed by a dot operator.
For example the statement D[i].printdist(); will print the distance value of ith
element of the array D.
We will demonstrate it by a program array.cpp containing array of distances.
//array.cpp
#include<iostream.h>
class distance
{
private:
int feet;
float inches;
public:
void getdist() //input length from user
{
cout<< “ enter feet:\n”;
cin>>feet;
cout<<”enter inches:”;
cin>> inches;
}
void printdist() // print the distance
{
cout<< feet << “\ ‘ -“ << inches << ‘\” ’;
}
};
int main()
{
distance D[50]; //array of distances
int count=0; // count the entries
char res; //response of user (y or n)
cout<< endl;
do
{
cout<< “ enter the value of distance:” << count+1;
D[n++].getdist(); //store distance in array
cout<< “ do you want to enter another distance (y/n)?:”;
cin>>res;
} while(res!= (’n’ || ‘N’))
for(j=0; j<count; j++)
{
cout<< “\ndistance number” << j+1 << “ is “;
D[j].showdist();
}
cout<<endl;
return 0;
}
In this program the user can enter the required number of distances.
After entering every distance. The program asks if user wants to enter
another distance value. If not, then the program terminates and prints all the
distances entered. Here is the output of the program when user enters three
distances.
enter distance number:1
enter feet:4
enter inches:5
do you want to enter another distance(y/n)? y
enter the value of distance:2
enter feet: 7
enter inches: 8
do you want to enter another distance(y/n)? n
distance number 1 is 4’ -5”
distance number 2 is 7’ -8”
Self Assessment Questions
7. There can be arrays of variables of type class and those variable are
called _________.
int inches;
public:
void setdistance(int c, int d)
{ feet=c;
inches=d;
}
void printdistance()
{ cout<<feet<<”ft”<<inches<<”inches;}
void adddist(distance d1, d2)
{ feet=d1.feet+d2.feet;
inches=d1.inches+d2.inches;
if (inches>12)
{ feet++;
inches=inches-12;
}
}
};
void main()
{ distance D1,D2,D3;
D1. setdistance(10, 2);
D2.setdistance(2,4);
D3.adddist(d1,d2);
D3.display();
}
In the above program, object D3 invokes the add function so the feet and
inches refer to invoking object’s data members. After adding the respective
data of D1 and D2 it is stored in D3 object.
Here item is a class and A is the object of the class item. You can define a
pointer iptr of type item as shown below:
item *iptr;
We use pointers in the situations where we do not know that how many
objects we have to create in a program. In that situation we use new
function to create objects at run time. The new function returns a pointer to
an unnamed object. Let us understand this concept with the help of an
example shown below.
//pointer.cpp
#include<iostream.h>
class distance
{
private:
int feet;
float inches;
public:
void getdist() //input length from user
{
cout<< “ enter feet:\n”;
cin>>feet;
cout<<”enter inches:”;
cin>> inches;
}
void printdist() // print the distance
{
cout<< feet << “\ ‘ -“ << inches << ‘\” ’;
}
};
int main()
{
distance D; //define a named distance object
D.getdist();
D.printdist();
distance *dptr; //pointer to distance class
dptr = new distance; //points to new distance object
dptr->getdsit(); // points to new distance object
dptr->printdist(); //access object members with -> operator
return 0;
}
The main() function defines dist, uses the Distance member function
getdist() to get a distance from the user and then uses printdist() to display
it.
Self Assessment Questions
8. We use ________ in the situations where we do not know how many
objects we need to create in a program.
9. The new function returns a pointer to an unnamed object. (True/False)
class container
{
public:
virtual double getvolume() = 0; //pure virtual function
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
The concept of pure virtual function is discussed in unit 8.
Abstract Class Example:
Let us see the following example where an interface is provided by parent
class to the base class to implement a function called getArea().
include <iostream.h>
// Base class
class shape
{
public:
// pure virtual function providing interface framework.
virtual int getarea() = 0;
void setlenght(int l)
{
length = l;
}
void setbreadtht(int b)
{
breadth = b;
}
protected:
int length;
int breadth;
};
// Derived classes
class rectangle: public shape
{
public:
int getarea()
{
return (length * breadth);
}
};
class square: public shape
{
public:
int getarea()
{
return (length*length);
}
};
int main()
{
rectangle rect;
square sq;;
rect.setbreadth(5);
rect.setlengtht(7);
// Print the area of the object.
cout << Area of rectangle is: " << rect.getarea() << endl;
sq..setlenght(5);
// Print the area of square.
cout << "Area of square is: " << sq..getarea() << endl;
return 0;
}
The result of the above program is as shown below:
Area of rectangle is: 35
Area of square is: 25
Rect r;
r.w = rectparam.w*2;
r.h = rectparam.h*2;
return (r);
}
int main () {
Rect r1, r2;
r1.setvalues (2,3);
r2 = duplicate (r1);
cout << r2.area();
return 0;
}
The function duplicate is a friend of Rect function. With the friend function
named duplicate, it is possible to access the members w and h of objects of
type rectangle. You can observe that the function duplicate is not a member
function of class Rect but it has access to the private members of the class
Rect.
Friend Classes
You should use friend class in the situation when the two classes are
strongly coupled. For example, suppose we have a class CCord that
represents a coordinate, and a class CCollect that holds a list of points. The
collections class may be used to change the point objects so we can
declare CCollect as a friend class of CCord.
// Forward declaration of friend class.
class CCollect;
// Point class.
class CCord {
friend CCollect;
private:
double m_x;
double m_y;
public:
CCordt(const double x, const double y):
m_x(x),
m_y(y) { }
~C Cord(void) { }
// ...
};
As you can see in the example above, the CCollect and CCord classes are
friend classes. Hence, CCollect class can access the data of any object of
CCord class. This is proved to be useful when you need to modify individual
elements of class CCollect. For example a setvalue method ofclass
CCollect can set all the values of the class CCord to a particular value.
class CCollect {
private:
vector<CCord> m_vecPoints;
public:
CCollect(const int nSize) :
m_vecPoints(nSize) { }
~CCollect(void);
void set(const double x, const double y);
// ...
};
The set member can iterate over the collection and reset each point:
void CCollect::set(const double x, const double y) {
// Get the number of elements in the collection.
const int nElements = m_vecPoints.size();
// Set each element.
for(int i=0; i<nElements; i++) {
m_vecPoints[i].m_x = x;
m_vecPoints[i].m_y = y;
}
}
The friendship is not mutual among friend classes. As in the above
example, CCollect class can access the data of CCord but the vice versa is
not true. The friendship is not passed down in the hierarchy of class. For
example the derived classes of CCollect will not be able to access the data
of CCord class. The principle is that it is not possible for a class to implicitly
grant friendship; each class must choose its friends explicitly.
Friend Scope
The friend function’s name or class which is introduced first in a friend
declaration is not in the scope of class granting friendship (also known as
the enclosing class). And also it is not a member of class granting
friendship.
The name of a function first introduced in a friend declaration is in the scope
of the first nonclass scope that contains the enclosing class. The body of a
function provided in a friend declaration is handled in the same way as a
member function defined within a class. Processing of the definition does
not start until the end of the outermost enclosing class. In addition,
unqualified names in the body of the function definition are searched for
starting from the class containing the function definition.
If we introduce a friend’s class name before the friend declaration, then the
compiler will search for a class name that matches with the name of the
friend class beginning at the scope of the friend declaration. If the name of a
friend class is introduced before the friend declaration, the compiler
searches for a class name that matches with the name of the friend class
beginning at the scope of the friend declaration. If the declaration of a
nested class is followed by the declaration of a friend class with the same
name, the nested class is a friend of the enclosing class.
The scope of a friend class name is the first nonclass enclosing scope. For
example:
class X {
class Y { // arbitrary nested class definitions
friend class Z;
};
};
is equivalent to:
class Z;
class X {
class Y { // arbitrary nested class definitions
friend class Z;
};
};
You have to use the scope resolution operator(::) if the friend function is a
member of another class. Example to explain this concept is shown below.
class X {
public:
int func() { }
};
class Y {
friend int A::func();
};
Friends of a base class are not inherited by any classes derived from that
base class. The following example demonstrates this:
class X {
friend class Y;
int p;
};
class Y { };
class Z : public Y {
void func(p* q) {
//q->p = 2;
}
};
The compiler would not allow the statement p->q= 2 because class Z is not
a friend of class X, although Z inherits from a friend of X.
Friendship cannot be transitive. The example below explains this concept.
class X {
friend class Y;
int p;
};
class Y {
friend class Z;
};
class Z {
Manipal University Jaipur B2114 Page No.: 99
Object Oriented Programming – C++ Unit 4
void func(pA* q) {
//q->p = 2;
}
};
The following statement q->a = 2 is not allowed by compiler as classes Z
and x are not friends, even though class Z is a friend of friend of X.
If you declare a friend in a local class, and the friend's name is unqualified,
the compiler will look for the name only within the innermost enclosing
nonclass scope. Before declaring a friend of a local scope you must declare
a function. However, the declaration of a friend class will hide a class in an
enclosing scope with the same name. The example to explain the concept is
shown below. The following example demonstrates this:
class X { };
void a();
void f() {
class Y { };
void b();
class A {
friend class X;
friend class Y;
friend class Z;
//friend void a();
friend void b();
//friend void c();
};
::X moocow;
//X moocow2;
}
The following statements will be allowed by the compiler in the above
example:
friend class X: This statement does not declare ::X as a friend of A, but
the local class X as a friend, even though this class is not otherwise
declared.
friend class Y: In the scope of f() the local class Y is declared. friend
class Z: This statement declares the local class Z as a friend of A even
though Z is not otherwise declared.
friend void b():In the scope of f() the function b() has been declared.
::X moocow: The object of the nonlocal class ::X is created by this
statement.
The following statements will not be allowed by the compiler: friend void a():
The function a() is not considered by this function in namespace scope. The
compiler will not allow this statement as the function a() is not declared in
scope of a(). friend void c(): The compiler will not allow this statement
because the function c() is not declared in the scope of f().X moocow2: This
statement attempt creating an object of the local class named X, and not the
nonlocal class ::X. This statement is not allowed by the compiler because
the local lass X is not defined.
Self Assessment Questions
12. Access to non-member functions or to another class is given in C++ by
using ____________ keyword.
13. In general practice the friend functions are listed in __________ of the
program.
prefixing the keyword static. You can call the static function by using the
name of the class and then the scope resolution operator followed by the
function name. The example below demonstrates the implementation of
static data and static functions.
//static.cpp
# include <iostream.h>
class X {
static int count;
int id;
public:
X()
{ count++;
id=count;
}
~X()
{ count--;cout<<"\n destroying ID number="<<id;
}
static void display_count()
{cout<<"endl "<<countl;}
void showid()
{cout<<"endl "<<id;}
};
int X::count=0;
void main()
{
X::display_count();();X x1, x2;
X::display_count();
x1.showid();
x2.showid();
}
You cannot declare the static and non-static member functions with the
same name, having same number and same type of arguments. A static
member function does not have this pointer. The following example
demonstrates this:
#include <iostream.h>
struct X
{
private:
int i;
static int si;
public:
void set_i(int arg) { = arg; }
static void set_si(int arg) { si = arg; }
void print_i() {
cout << "Value of i = " << i << endl;
cout << "Again, value of i = " << this->i << endl;
}
static void print_si() {
cout << "Value of si = " << si << endl;
//cout << "Again, value of si = " << this->si << endl;
}
};
int X::si = 77; //Initialize static data member
int main() {
X xobj;
xobj.set_i(11);
xobj.print_i();
//static data members and functions belong to the class and
//can be accessed without using an object of class X
X::print_si();
X::set_si(22);
X::print_si();
}
Manipal University Jaipur B2114 Page No.: 104
Object Oriented Programming – C++ Unit 4
Output:
Value of i = 11
Again, value of i = 11
Value of si = 77
Value of si = 22
As the member function A::print_si() is declared as static and hence, it does
not have this pointer. So the member access operation this->si is not
allowed by the compiler.
You can call a static member function using this pointer of a non-static
member function. In the following example, the non-static member function
printall() calls the static member function f() using this pointer:
#include <iostream.h>
class A {
static void xyz() {
cout << "The value of p is:: " << p<< endl;
}
static int p;
int q;
public:
A(int q1): q(q1) { }
void print();
};
void A::print() {
cout << "the value of q is:: " << this->q << endl;
this->xyz();
}
int A::p = 3;
int main() {
A obj_A(0);
obj_A.print();
}
Output:
the value of q is: 0
the value of p is: 3
It is not allowed in C++ to declare a static member function with the
following keywords: virtual, const, volatile, or const volatile. Only the names
of the following can be accessed by a static member function: static
members, enumerators, and nested types of the class in which it is
declared. A static member function cannot be declared with the keywords
virtual, const, volatile, or const volatile. A static member function can access
only the names of static members, enumerators, and nested types of the
class in which it is declared. Suppose a static member function A() is a
member of class C. The static member function A() cannot access the non-
static members C or the non-static members of a base class of C. The
figure 4.2 summarizes member functions and data of a class
Member Function1
Member Function2
Static Function
Static Data
4.12 Summary
Classes provide users a way to create user defined data type.
Object is an instance of a class and is used in the program to store data.
Pointers can point to simple data types, arrays and to objects as well.
We use pointers in the situations where we do not know that how many
objects we have to create in a program.
An abstract class is the class which acts as a base class and can be
inherited by other classes and is not used to create objects.
Every time when the program creates a class instance, a special pointer
is created in C++ called this and it contains the address of the current
object instance.
Friend functions allow us to access some non-member functions or
other classes in C++.
With the possibility of selecting a non-member friend function, there are
two more options for its friends. These options are that either the class
can declare as a friend a member function of another class or another
class also can be declared as a friend.
Static data member of the class is one data member that is common for
all the objects of the class and are accessible for the class.
4.14 Answers
Self Assessment Questions
1. Class
2. Abstract
3. Object
4. True
5. Public, private and protected
6. private and public
7. Array of objects
8. Pointers
9. True
10. this
11. False
12. Friend
13. Beginning
14. Static Functions
15. Member functions
16. False
Terminal Questions
1. Every time when the program creates a class instance a special pointer
is created in C++ called this that contains the address of the current
object instance. For more details refer section 4.9.
2. Classes provide users a way to create user defined data types. Classes
provide a convenient way to group related data and the methods that
operate on data together. For more details refer section 4.2.
3. The name of a function first introduced in a friend declaration is in the
scope of the first nonclass scope that contains the enclosing class. For
more details refer section 4.10.3.
4. With the possibility of selecting a non-member friend function, there are
two more options for its friends. These options are: either the class can
declare a member function of another class as a friend or another class
can also be declared as a friend. For more details refer section 4.10.2.
5. Static data member of the class is one data member that is common for
all the objects of the class and is accessible for the class. Static
functions are special type of functions which can be invoked even
without an object of the class. For more details refer section 4.11.
References:
Object Oriented Programming In C++, 4/E by Robert Lafore. Pearson
Education India.
Object Oriented Programming with C++ - Sixth Edition, by
E Balagurusamy. Tata McGraw-Hill Education.
Object-Oriented Programming Using C++, By Joyce Farrell. Cengage
Learning.
5.1 Introduction
In the previous unit you studied classes, objects and procedure to define
them. You also learnt the abstract classes and friend functions and their use
in C++. In this unit you study constructors and destructors. There are
several special C++ member functions that determine how the objects of a
class are created, initialized, copied, and destroyed. Constructors and
destructors are the most important of these. They have many of the
characteristics of normal member functions – you declare and define them
within the class, or declare them within the class and define them outside -
but they have some unique features. In this unit we will discuss the role of
constructor and overloading constructor. We will also focus on destructor
with its role to de allocate the objects which were created by the constructor.
Objectives:
After studying this unit you should be able to:
explain the use constructors.
discuss overloading constructor.
describe the role of destructors.
5.2 Constructors
Constructors are member functions of a class and have the same name as
the class name. Constructors are called automatically whenever an object of
the class is created. This feature makes it very useful to initialize the class
data members whenever a new object is created. It can also perform any
other function that needs to be performed for all the objects of the class
without explicitly specifying it.
A constructor knows only to build an object of its own class. Constructors
aren't automatically inherited between base and derived classes. If the
constructors are not provided in the derived class then C++ will provide a
default constructor but it may not perform the functions as you like. And if
you do not provide a constructor, the C++ will create a default constructor
with no parameters in it. The default constructor will not be created if you
provide a constructor in the derived class.
Characteristics of a constructor
These are the functions having the name similar to its class. Their role is
to initialize the class members when an object of the class is created.
They should be declared in public section of class for availability to other
functions.
No return type, not even void is specified for the constructors.
They cannot be inherited but the derived class can call the constructor
of its baser class.
They can call member functions of its class.
They cannot be virtual.
They can have default values and can be overloaded.
It is possible to create multiple constructors of the same class but they
should have different parameters so that they can be easily
distinguished.
The syntax to define a constructor is as follows:
class classname
{
public:
classname(); //constructor
classname(argument list); //another constructor
…
};
{
point p1;
cout<<”point p1 (“ << p1.x << “,” << p1.y << “)” << endl;
point p2(5);
cout<<”point p2 (“ << p2.x << “,” << p2.y << “)” << endl;
point p3(10,10);
cout<<”point p3 (“ << p3.x << “,” << p3.y << “)” << endl;
}
In the above program you can see the point class having two data members
x and y and three constructors. The first constructor is without any
arguments and initializes both the data members to zero. The second
constructor takes a parameter of integer type. In that one data member is
initialized with the parameter x1 passed to the constructor and another is
initialized with zero. The last constructor takes two arguments. The data
members are initialized with the parameters x1 and y1 passed to the
constructor. When a constructor is called, a message is printed on the user
console.
Constructor pitfalls are:
As mentioned above, defining any constructor explicitly requires explicitly
defining a default constructor if needed.
Defining constructors that take only one parameter allows the constructor to
be implicitly used by the compiler to convert from the parameter type to the
class type of the constructor. This is OK in many situations, such as
converting a string literal to a string class instance. However in many other
places it does not make sense. For example, a vector (single dimensional
array) class that takes an integer type parameter to specify an initial number
of elements in the vector object. In this case such an integer type can be
implicitly converted to a vector type - which is probably not too useful and
will probably hide errors (bugs!). In such cases you have to mark the
constructor explicit:
class Vector
{
public:
explicit Vector( unsigned int size );
// ...
};
{
point *p1 = new point(); // it calls no argument constructor f the point class
and prints the values of data members in user
console.cout<<”point p1 (“ << p1.x << “,” << p1.y << “)” << endl;
point *p2= new point(5); // it calls a single argument constructor and
initializes x to 5 and y to 0.
cout<<”point p2 (“ << p2.x << “,” << p2.y << “)” << endl;
point *p3= new point(10,10); //it calls the two argument constructor which
initializes both x and y to 10.
cout<<”point p3 (“ << p3.x << “,” << p3.y << “)” << endl;
}
int x,y;
public:
point( int x1, int y1)
{
x=x1;
y=y1;
cout<<”constructor called\n”;
};
point (point &p)
{
x=p.x;
y=p.y;
cout<<” copy constructor is called”;
}
};
void main()
{
point p1(5,5);
cout<< “point p1 (“ << p1.x << “,” << p1.y << “)” << endl;
point p2(p1)
cout << “point p2 (“ << p2.x << “,” << p2.y << “)” << endl;
//testing for two objects
cout << “” setting data members of two objects\n”;
p1.x =10; p1.y=10;
p2.x=20, p2.y=20;
cout<< “point p1 (“ << p1.x << “,” << p1.y << “)” << endl;
cout << “point p2 (“ << p2.x << “,” << p2.y << “)” << endl;
}
As you can see in the above example, two constructors are declared in the
point class, i.e. the constructor with two arguments and a copy constructor.
We create an object p1 that sets both data members of the point object to
the value 5. The program prints these values on the user console for
verification.
Manipal University Jaipur B2114 Page No.: 117
Object Oriented Programming – C++ Unit 5
point p1(5,5);
cout<< “point p1 (“ << p1.x << “,” << p1.y << “)” << endl;
The statement point p2(p1) makes the use of copy constructor to construct
object p2 of type point.
You will also want to verify that the two independent objects are created by
the program. For this, as you can see in the program, individual data
members of the two objects have to be set to different values and dumped
the two objects on console. The following code member does this.
cout << “setting data members of two objects \n”;
p1.x =10; p1.y = 10;
p2.x =20, p2.y =20;
cout<< “point p1 (“ << p1.x << “,” << p1.y << “)” << endl;
cout << “point p2 (“ << p2.x << “,” << p2.y << “)” << endl;
5.6 Destructors
Destructors are the member functions that are called automatically when an
object of a class is destroyed or goes out of scope. It also performs cleanup
work necessary before an object is destroyed. Likewise constructor the
name of the destructor is also similar to its class and is prefixed by a ~
(tilde). For example:
class A
{
public:
// Constructor for class A
A();
// Destructor for class A
~A();
};
Characteristics of a destructor:
Destructors are called automatically when an object of a class is
destroyed.
They are declared in public section of a class.
They don’t have any return type (not even void) and do not take any
argument as well.
They cannot be declared const, volatile, const volatile or static. A
destructor can be declared virtual or pure virtual.
If no user-defined destructor exists for a class and one is needed, the
compiler implicitly declares a destructor. This implicitly declared
destructor is an inline public member of its class.
They cannot be inherited. But the derived class can invoke the
destructors of the base class.
They cannot be overloaded.
They can call other member functions of its class.
The compiler will implicitly define an implicitly declared destructor when the
compiler uses the destructor to destroy an object of the destructor's class
type. Suppose a class A has an implicitly declared destructor. The following
is equivalent to the function the compiler would implicitly define for X:
X::~X() { }
The following program implements the constructor and destructors for a
class
// constdest.cpp
# include<iostream.h>
class example
{ private:
int a;;
public:
example() {a=0; cout<<”Constructor invoked”<<endl;}
~example() {cout<<”Destructor invoked”;}
void show()
{ cout<<”Data is=”<<a<<endl;}
};
void main()
{ example e1;
e1.show();
}
If you run the above program you will get the output as follows:
Constructor invoked
Data=0
Destructor invoked
When an object e1 of example class is created, the constructor is invoked
automatically and data value is initialized to zero. When the program is
terminated the object is destroyed and the destructor is automatically
invoked. When the program ends the object is destroyed which invokes the
destructor. Please note that both the constructor and destructor are
declared as public and they have no return value. The following program
implements the overloaded constructors for the distance class.
//overloadconst.cpp
#include<iostream.h>
class distance
{ private:
int feet;
int inches;
public:
distance()
{ feet=0;
inches=0;}
distance(int ft, int i)
{ feet=ft;
inches=i;}
void print()
{ cout<<feet<<”feet”<<inches<<”inches;}
};
void main()
Manipal University Jaipur B2114 Page No.: 120
Object Oriented Programming – C++ Unit 5
Destructors for non-virtual base classes are called before destructors for
virtual base classes are called.
When an exception is thrown for a class object with a destructor, the
destructor for the temporary object thrown is not called until control passes
out of the catch block. When an automatic object (an object which is
declared auto or register or not declared as static or extern) or a temporary
object passes out of scope, then the destructors are implicitly called. They
are implicitly called at program termination for constructed external and
static objects. Destructors are invoked when you use the delete operator for
objects created with the new operator. For example
#include <string>
class A
{
private:
char * string;
int n;
public:
// Constructor
A(const char*, int);
// Destructor
~A() { delete[] string; }
};
// Define class A constructor
A::A(const char* p, int x)
{
string = strcpy(new char[strlen(p) + 1 ], p);
nr = x;
}
int main ()
{
// Create and initialize
// object of class A
A aobj = A("somestring", 10);
// ...
// Destructor ~A is called before
// control returns from main()
}
The destructors can be used explicitly to destroy the objects, even though
this method is not recommended. However to destroy an object created with
the new operator, you can explicitly call the object's destructor. This concept
is explained in the example below:
#include <iostream.h>
class X
{
public:
X() { cout << "X::X()" << endl; }
~X() { cout << "X::~X()" << endl; }
};
int main () {
char* ptr = new char[sizeof(X)];
X* xptr = new (ptr) X;
xptr->X::~X();
delete [] ptr;
}
The statement X* aptr =new(ptr) X creates a new object of type X
dynamically. The object is created not in the free store but in the memory
allocated by ptr. The storage allocated by ptr will be deallocated by the
statement delete [] ptr. But the run time will still believe that the object
pointed to by ap still exists until you explicitly call the destructor of X (with
the statement aptr->X::~X()).
Self Assessment Questions
6. Destructor takes arguments and returns value. State (True/False)
7. The destructor for a ________________ is called before destructors for
members and bases are called.
8. Destructors are declared in ______ section of a class.
9. Destructors can be overloaded. (True/False)
Manipal University Jaipur B2114 Page No.: 123
Object Oriented Programming – C++ Unit 5
Let us see how namespace scope the entities including variable and
functions:
#include <iostream>
using namespace std;
// first name space
namespace f1_space{
void f1()
{
cout << "this is the first name space" << endl;
}
}
// second name space
namespace f2_space
{
void f2(){
cout << "this is the second namespace" << endl;
}
}
int main ()
{
// Calls function from first name space.
f1_space::f1();
You can also use the directive to refer to a particular item within a
namespace. For example, if the only part of the std namespace that you
intend to use is cout, you can refer to it as follows: using std::cout;
Self Assessment Questions
11. A _______ is a certain scope for identifiers. Unlike a class, it is open
for extensions that might occur at any source.
12. We can also avoid prepending of namespaces with the using
namespace directive. (True/False).
5.8 Summary
Constructors are member functions of a class, which have same name
as the class name and are called automatically whenever an object of
the class is created.
We can declare multiple constructors of a class and it is called
constructor overloading.
Defining constructors that take only one parameter allows that
constructor to be implicitly used by the compiler to convert from the
parameter type to the class type of the constructor.
We can call a parameterized constructor while creating an object
dynamically. The required list of parameters is enclosed in the
parentheses while we call the constructor with no arguments of the point
class.
In some situations, you may require to create a copy of an already
existing object this can be done by using copy constructors.
Destructors are the member functions that are called automatically when
an object of a class is destroyed or goes out of scope.
The destructors of base classes and members are called in the reverse
order of the completion of their constructor.
A namespace is a certain scope for identifiers. Unlike a class it is open
for extensions that might occur at any source.
We can also avoid prepending of namespaces with the ‘using’
namespace directive.
5.10 Answers
Self Assessment Questions
1. Constructor
2. Default
3. Constructor overloading
4. Copy constructor
5. Argument
6. False
7. class object
8. Private
9. False
10. True
11. Namespace
12. True
Terminal Questions
1. //stack.cpp
# include <iostream.h>
# define size 100
class stack
{ int stck[size];
int top;
public:
stack() {top=0;
cout <<"stack initialised"<<endl;}
~stack() {cout <<"stack destroyed"<<endl;}
void push(int i);
int pop();
};
void stack::push(int i)
{
if (top==size)
{ cout <<"stack is full";
return;
}
stck[top]=i;
top++;
}
int stack ::pop()
{ if (top==0) {
cout << "stack underflow" ;
return 0;
}
top--;
return stck[top];
}
void main()
{ stack a,b;
a.push(1);
b.push(2);
a.push(3);
b.push(4);
cout<<a.pop() << " ";
cout<<a.pop()<<" ";
cout<<b.pop()<< " ";
cout<<b.pop()<<endl;
}
2. Overloaded Constructor Invoked
12
12
Overloaded constructor Invoked
10
22
3. Constructors are member functions of a class which have same name
as the class name. Constructors are called automatically whenever an
object of the class is created. This feature makes it very useful to
6.1 Introduction
In the previous unit you have studied the constructors, their different types
and their use in C++. You have also studied the destructors and the
namespaces in C++. In this unit you study the concept of operator
overloading. You will also learn how to overload different operators in C++.
You will also know the method of performing type conversions in C++.
Operator overloading is the ability to tell the compiler how to perform a
certain operation when its corresponding operator is used on one or more
variables. Operator overloading, less commonly known as operator ad-hoc
polymorphism, is a specific case of polymorphism, where different operators
have different implementations depending on their arguments. Operator
overloading is generally defined by the language, the programmer, or both.
Operator overloading is claimed to be useful because it allows the
developer to program using notation "closer to the target domain” and
allows user-defined types a similar level of syntactic support as types built
into the language. In this unit we are going to discuss unary and binary
operator overloading with examples.
Objectives:
After studying this unit, you should be able to:
explain operator overloading
describe unary operator overloading
describe binary operator overloading
discuss type conversion
Manipal University Jaipur B2114 Page No.: 132
Object Oriented Programming – C++ Unit 6
sizeof operator
preprocessor symbol (#)
A special function called and operator function is used to overload an
operator. It defines the operations that the overloaded operator will perform
on the objects of the class for which it is redefined. An operator function is
defined either as a public function or as a friend function. You must follow
the following steps to overload an operator:
Create the class for which an operator is to be overloaded.
Declare the function either as a public function or a friend function.
Define the operator either inside the class definition (member function)
or outside the class (friend function).
The syntax to define the member operator function inside the class is
return_type operator op (parameter list)
{
//function body
}
Example: int operator + (int a, int b)
If you are defining member function outside the class you have to
declare it first inside the class. The following is the syntax to declare the
member function inside the class:
return_type operator op (parameter list);
The following is the syntax to define member operator function outside
the class:
return_type class_name:: operator op (parameter_list)
{
//function body
}
Example: int test :: operator + ( int a, int b)
Where return_type(int) = data type of the value returned by the function
operator is C++ keyword
c1++;
++c1;
cout<<c1.getcount();
}
c2=++c1;
cout<<c1.getcount()<<endl;
cout<<c2.getcount();
}
In the example shown above you can see that a counter variable is returned
without creating a variable. In the above implementation, we are returning
the counter variable without creating a variable. It is done by using a
constructor having one argument. When the statement return counter(c) is
executed, the value of the argument c of the invoking object is passed to the
constructor and a nameless object is created which is initialized to the value
stored in the count and returned to the calling program. One argument
constructor is used in this case. We are using one argument constructor in
this case.
The limitation of unary operator overloading is that the increment and
decrement operators cannot be totally duplicated. The reason is that the
C++ compiler is not able to differentiate between pre and post increment/
decrement operators.
Self Assessment Questions
4. Unary operators are implemented with _____ arguments.
5. Unary operators should have return value as ________.
6. Unary operators overloaded for the class can differentiate between
post and pre operators. (True/False)
{
float x; //real part
float y; //imaginary part
public:
complex(){ } //constructor1
complex( float real, float imag) //constructor2
{
x=real;
y=imag;
}
complex operator+(complex c);
void display(void);
};
complex complex:: operator+(complex c)
{
complex temp; //temporary
temp.x = x + c.x;
temp.y = y + c.y;
return(temp);
}
void complex :: display(void)
{
cout << x << “+ j” << y << “\n”;
}
int main()
{
complex c1, c2, c3; //invokes constructor1
c1= complex(2.5, 3.5); //invokes cosntructor2
c2=complex(1.6, 2.7);
c3=c1+c2;
cout<< “c1 = ” ;
Manipal University Jaipur B2114 Page No.: 139
Object Oriented Programming – C++ Unit 6
c1.display();
cout<<”c2 = ”;
c2.display();
cout<<”c3 = ”;
c3.display();
return 0;
}
Here is the output of the above program:
c1= 2.5 + j3.5
c2 = 1.6 + j2.7
c3 = 4.1 + j6.2
Let us look at the following function:
complex complex :: operator+(complex c)
{
complex temp; //temporary
temp.x = x + c.x;
temp.y = y + c.y;
return(temp);
}
{feet=0; inches=0;}
distance(int f)
{feet=f; inches=0;}
distance(int f, int i)
{feet=f;inches=i;}
void display()
{cout<<feet <<" "<<inches<<endl;}
friend distance operator + (distance, distance);
};
distance operator + (distance d1, distance d2)
{ int f = d1.feet+d2.feet;
int i = d1.inches+d2.inches;
return distance(f,i);}
void main()
{
distance d1(2,5), d2;
d2=10+d1;
d2.display();
}
Let us now study how the relational operators can be overloaded. In this
situation also there can be either one argument or two argument
overloading (using friend function). But the return value should be integer (0
or 1) which indicates true or false.
The following program implements the program for relational operator
overloading (<) for the distance class.
# include<iostream.h>
class distance
{ private:
int feet, inches;
public:
distance()
{feet=0; inches=0;}
distance(int f)
{feet=f; inches=0;}
distance(int f, int i)
{feet=f;inches=i;}
void display();
void getdata();
int operator < (distance d1)
{ if (feet<d1.feet)
return 1;
else if (feet==d1.feet) && (inches<d1.inches)
return 1;
else
return 0;
}
};
void distance :: display()
{cout<<feet <<" "<<inches<<endl;}
void distance :: getdata()
{ cout<<”Enter distance in feet and inches”;
cin>>feet >>inches;}
void main()
{
distance d1,d2;
d1.getdata();
d2.getdata();
if (d1<d2)
cout<<d1.display() << “is smaller”;
else
cout<<d2.display()<< “ is smaller”;
}
Manipal University Jaipur B2114 Page No.: 144
Object Oriented Programming – C++ Unit 6
As you can see in the above program the object d1 is responsible for
invoking the operator < whereas object d2 is passed as an argument. The
value returned by the overloaded operator function is either 1 or 0 which
indicates true or false respectively. Certain compilers support boolean
datatype which can be alternatively used instead of integer. The display and
getdata member functions are implemented in a different way in the above
program. You can observe that the member functions are declared inside
the class but defined outside the class. The class name with the function
name separated by scope resolution operator (::) is used to specify that the
member function belongs to the distance class.
Self Assessment Questions
7. Member functions of a class can be defined outside the class using
________ operator along with the class name.
8. In most of the cases same result is generated either by using member
function or by using friend function. (True/False).
9. Overloaded relational binary operators should return _________.
10. Left operand calls the operator in case of binary operator overloading.
(True/False).
6.6 Summary
Operator overloading allows defining new meaning for normal C++
operators and specifies how it can be used with the user defined classes.
Overloading should be used only to imply default meanings to avoid
confusion in its usage.
Not all operators can be overloaded. C++ enables the programmer to
overload most operators to be sensitive to the context in which they are
used.
The compiler generates the appropriate code based on the operator's
use. Operator overloading contributes to C++'s extensibility.
Operator overloading provides the same concise expressions for user-
defined types that C++ provides with its rich collection of operators that
work on built-in types.
The precedence and associativity of an operator cannot be changed by
overloading.
6.8 Answers
Self Assessment Questions
1. True
2. True
3. operator
4. No
5. Same as class datatype
6. False
7. scope resolution operator
8. True
9. Integer or Boolean values
10. True
11. Type Conversion
12. Castings
Terminal Questions
1. //string.cpp
# include<iostream.h>
# include<ctype.h>
# include<string.h>
# include<conio.h>
class string
{ char str[25];
public:
string()
{ strcpy(str, "");}
string(char ch[])
{ strcpy(str, ch);}
void display()
{ cout<<str;}
string operator ++()
{string temp;
int i;
for(i=0;str[i]!='\0';i++)
temp.str[i]=toupper(str[i]);s
temp.str[i]='\0';
return temp;
}
};
void main()
{ clrscr();
string s1="hello", s2;
s2=s1++;
s2.display();
getch();
}
2. //stringar.cpp
# include<iostream.h>
# include<ctype.h>
# include<string.h>
# include<conio.h>
class string
{ char str[25];
public:
string()
{ strcpy(str, "");}
string(char ch[])
{ strcpy(str, ch);}
void display()
{ cout<<str;}
void operator +=(string s2)
{int i,l,j;
l=strlen(str);
for(i=l,j=0; s2.str[j]!='\0'; i++,j++)
str[i]=s2.str[j];
str[i]='\0';
}
};
void main()
{ clrscr();
string s1="hello", s2="world";
s1+=s2;
s1.display();
getch();
}
3. In case of overloading of unary operators, the calling operand can be
either left or right of the operator as in case of increment and decrement
operators. While defining the operator functionality for the class, the
keyword operator is used. Refer section 6.3 for more details.
Manipal University Jaipur B2114 Page No.: 152
Object Oriented Programming – C++ Unit 6
References:
Object Oriented Programming with C++ - Sixth Edition, by
E Balagurusamy. Tata McGraw-Hill Education.
Object-Oriented Programming using C++, by Satchidananda Dehuri,
Alok Kumar Jagadev, Amiya Kumar Rath. PHI Learning Pvt. Ltd.
Unit 7 Inheritance
Structure:
7.1 Introduction
Objectives
7.2 Inheritance in C++
7.3 Public, Private and Protected Inheritance
7.4 Types of Inheritance
7.5 Function Overriding
7.6 Multiple Inheritance
7.7 Constructors in derived classes
7.8 Summary
7.9 Terminal Questions
7.10 Answers
7.1 Introduction
In the previous unit you studied about operator overloading and type
conversions. In this unit you are going to study the concept of inheritance.
You will learn about types of inheritance and multiple inheritances. The
method by which new classes called ‘derived classes’ are created from the
exiting classes called ‘base classes’ is known as ‘inheritance’. The derived
classes have all the features of the base class and the programmer can
choose to add new features specific to the newly created derived class. For
example, you can create a base class called ‘employee’, and define the
derived classes as manager, supervisor, accountant etc. All of these derived
classes have all the features of their base class (employee), and yet differ
because they have some more specific features added.
Objectives:
After studying this unit you should be able to:
explain the concept of inheritance
discuss base and derived classes
describe public, private and protected inheritance
discuss function overriding
discuss the different types of inheritance
explain multiple inheritances
explain constructors in derived classes
# include<string.h>
# include<conio.h>
class employee
{
protected:
int empno;
char ename[25];
public:
employee()
{ empno=0;
strcpy(ename,"");
}
employee(int n, char ch[25])
{ empno=n;
strcpy(ename,ch);
}
void display()
{cout<<"Emp Code:"<<empno;
cout<<"Name:"<<ename;
}
};
class manager: public employee
{
protected:
float basic;
float hra;
public:
manager():employee()
{ basic=0.0; hra=0.0;}
manager(int n, char ch[25],float i, float j): employee(n,ch)
{ basic=i; hra=j;}
void display()
{ employee ::display();
cout<<"Basic"<<basic<<endl;
cout<<"HRA"<<hra<<endl;
}
};
Manipal University Jaipur B2114 Page No.: 157
Object Oriented Programming – C++ Unit 7
void main()
{
clrscr();
employee e1(106,"amit");
manager m1(205,"pawan",40000.00,5000.00);
e1.display();
m1.display();
getch();
}
As you can see, in the above program, there is a class employee having
data member’s empcode and ename. These are declared as protected data
members so that they can be inherited by the derived class. The employee
class contains two constructors and a member function named ‘display’.
We have derived the manager class form the class employee using the
following statement:
class manager: public employee
Here public is a keyword which specifies that the class is derived publically
from the class employee. You will study the types of inheritance in the next
section. The derived manager class will have inherited data members
i.e. ename and empcode of the base class employee. It also contains its
own data members i.e. basic and hra.
The derived manager class also contains the constructors and a member
function named as ‘display’. In the class manager also, we have defined
constructors and a member function display. While initializing the data
members of the manager class, the respective members of the parent class
will also have to be initialized. The constructors of the parent class are
invoked by the following statements: manager(): employee()
manager(int n,char ch[25],float i, float j): employee(n,ch)
You can also assign default values to the members.
While displaying the contents of the manager class, respective members of
the parent class are also displayed. The display function of the base class is
invoked in ‘the display function’ of the derived class. This is done by the
following statement:
employee::display()
As you can see, the class name, followed by the scope resolution operator,
is used to refer the function name belong to the class. When both the base
class and the derived class have a function with the same name, the
object.functionname statement with the base class object will always access
function defined in the base class as the base class does not know anything
about the derived classes. If the object is a derived class object, then the
function defined in the derived class will be invoked. This feature is known
as function overriding. If the function is not defined in the derived class, then
the object will access the function in the parent class.
Self Assessment Questions
1. The derived class object can access ____ members of the parent class.
2. The derived class member functions can access _____________
members of the parent class.
3. Inheritance allows ___________ of the program code.
Vehicle
Base class
Taxi
Derived class
Figure 7.1: Single inheritance
In the above figure 7.1 vehicle is the base class and the taxi is the derived
class, which describes the vehicle of a special type.
2. Multiple Inheritance
The derived class can also have multiple parents, which is known as
multiple inheritance. Here the child - or the derived class - has two or more
parent classes as depicted in figure 7.2. The child class inherits all the
properties of all its parents. Multiple inheritance is implemented in a similar
way as single inheritance except that both the parent names have to be
specified while defining the class.
3. Multi-level Inheritance
When a class is derived from the derived class it is known as multilevel
inheritance. In such case, the grandchild class inherits all the properties of
the child and the parent classes as shown in figure 7.3.
Shape
Base or parent class
Rectangle
Child class
Rounded Rectangle
Grandchild class
Figure 7.3: Multi-level Inheritance
4. Hierarchical Inheritance
Many programming problems are cast into hierarchy when certain features
of one level are shared by many others below that level. The example of the
5. Hybrid Inheritance
If we apply more than one type of inheritance to design a problem, then it is
known as hybrid inheritance. Here, a new class can be created from
multiple and multi-level classes, or from the multiple and hybrid classes. The
figure 7.5 shows an example of hybrid inheritance using multiple and multi-
level inheritance.
As you can see in the above figure, the child may inherit features from the
grandparents, father and mother. Here inheriting the features of grandparent
};
class B: public A
{
public:
void show ()
{
cout<< “ derived class”;
}
};
void main()
{
A obj1; //object of base class
B obj2; //object of derived class
obj1.show(); // calls the function show defined in base class A
obj2.show(); // calls the function show defined in derived class B
}
Self Assessment Questions
7. ________ is the process in which a class is inherited in the derived
class and the one of the functions of the base class is again defined in
the derived class.
8. The function which is overridden can have different definitions in both
the derived and the base classes. (True/False)
Here base1, base2, baseN are direct bases of Derived, and each of them
should have a distinct name.
An access_type can be private, public or protected, and follows the same
access rules as single inheritance.
The keyword ‘virtual’ is optional, and specifies a sharable base.
Member functions or data that have the same name in base1, base2 or
baseN are potential ambiguities.
Here are several examples of multiple inheritance declarations:
class A : public B, public C { ….. };
Class A derives publically from base classes B and C like single inheritance.
class D: public E, private F, public G{…..};
Class D derives publically from E and G and privately from F. This
derivation makes D a subtype pf E and G and not a subtype of F. C
class X: Y, Z {….};
Class X derives privately from both y and Z by default as no access
specifier is mentioned.
class M: virtual public N, virtual public p {….};
Here N and P are virtual bases of M. which we will discuss in unit 8.
Let us implement a program where there are two classes namely ‘student’
and ‘employee’. We shall derive a class manager from the above two
classes and see how member functions and constructors are implemented
in multiple inheritance:
//multiple.cpp
# include<iostream.h>
# include<string.h>
# include<conio.h>
class student
{protected:
char qual[6]; // highest degree earned
int percent; // percentage score in the last degree
public:
student()
{ employee::display();
student::display();
cout<<endl <<"Basic"<<basic;
cout<<endl <<"HRA"<<hra;
}
};
void main()
{
clrscr();
manager m1(205, “pawan”, “MBA”, 80, 40000.00, 5000.00);
m1.display();
getch();
}
As you can see in the above program, both the parent class and
constructors are called by the constructors of derived class. This is because
every object of the derived class has its own copy of parent data members.
Therefore, their initializations too is required. The parent class member
functions are invoked using the scope resolution operator as shown in the
display function of the manager class.
The output of the above program will be:
Emp Code:205
Name:pawan
Qualification MBA
Score 80
Basic 40000
HRA 5000
Ambiguity in multiple Inheritance
There are several types of ambiguities that might arise in the process of
implementation of multiple inheritance. Let us suppose that there are two
parent classes P and Q. And class R is the derived class of P and Q.
Suppose that there is a function ‘func1()’ defined in both the parent classes
P and Q, but this func1() has not been defined in the child class. When the
child class object (obj) tries to access the function func1() through a
statement obj.func1(), there is compiler error. The reason is that this
statement is ambiguous for the compiler as it will not be able to find out
class X
{protected:
int a;};
class Y: public parent
{ };
class Z: public parent
{ };
class P: public X, public Y
{ public:
int f1()
return a; //ambiguous
};
baseN(arglistN),
{
Body of derived constructor
}
void show_mn(void)
{
cout<< “m = “ << m << “\n” << “n=” << n << “\n”;
}
};
void main()
{
gamma g(5, 10, 75, 20, 30)
cout << “\n”;
g.show_x();
g.show_y();
g.show_mn();
}
The output of the program will be:
beta initialized
alpha initialized
gamma initialized
x=5
y=10.5
m=20
n=30
Self Assessment Questions
12. In the case of __________ the base classes are constructed in the
order in which they appear in the declaration of the derived class.
13. The constructors of the virtual base classes are invoked before any
non-virtual base classes. (True/False)
7.8 Summary
Inheritance allows creating a class known as derived class from a class
known as base class, and inheriting all the properties of the parent class
allows programs to be reused without rewriting entire code.
The members that can be inherited have to be declared using protected
access specifier. There can be several levels of inheritance and the
derived class can be inherited from multiple parents as well.
Inheritance helps the code to be reused in many situations and this
concept of reusability saves the programmer’s time and effort.
7.10 Answers
Self Assessment Questions
1. public
2. public and protected
3. reusability
4. Multiple Inheritance
5. Private Inheritance
6. True
7. Function overriding
8. False
9. Multiple inheritance
10. True
11. Diamond Inheritance
12. Multiple Inheritance
13. True
Terminal Questions
1. Output is:
Null Constructor for A
Null Constructor for A
Null Constructor for B
Null Constructor for A
Int Constructor for B
Null Constructor for A
Null Constructor for B
Null Constructor for C
Null Constructor for A
Int Constructor for B
Int Constructor for C
2. Output is
Null Constructor for A
Null Constructor for B
Null Constructor for C
Destructor for C
Destructor for B
Destructor for A
3. A derived class can be defined as follows:
class derived_classname: access specifier baseclassname
{
Members of derived class
};
The access specifer can be public, private or protected. Depending on
the access specifier, the inheritance can be public, private or protected.
(Refer section 7.3 for more details).
4. The different types of inheritance are: Single Inheritance, Multiple
Inheritance, Multi-level Inheritance, Hierarchical Inheritance, and Hybrid
Inheritance. (Refer section 7.4 for more details).
5. There are several types of ambiguity that might arise during the
implementation of multiple inheritance. Let us suppose that there are
two parent classes P and Q. And class R is the derived class of P and Q.
Suppose further that there is a function func1() defined in both the
parent classes P and Q, but func1() has not been defined in the child
class. When the child class object (obj) tries to access the function
func1() through a statement obj.func1(), there is a compiler error. The
reason is that this statement is ambiguous for the compiler, as it will not
be able to find out which parent’s f1() function is called. Another
common ambiguity that arises is in the case of diamond inheritance.
(Refer section 7.6 for more details).
6. If a class is inherited in the derived class, and one of the functions of the
base class is again defined in the derived class, then that function is
said to be overridden, and this procedure is known as function overriding.
(Refer section 7.5 for more details).
7. If there is a constructor in any base class with one or more arguments,
then it is compulsory for the derived class to have a constructor and
Manipal University Jaipur B2114 Page No.: 177
Object Oriented Programming – C++ Unit 7
References:
Object-Oriented C++ Programming, First edition, by Hirday Narayan
Yadav. Firewall Media.
Interfacing with C++: Programming Real-World Applications,
by Jayantha Katupitiya, Kim Bentley. Springer Science & Business
Media.
Object-oriented Programming with C++ - Sixth Edition,
by E Balagurusamy. Tata McGraw-Hill Education.
http://www.programiz.com/
Structure:
8.1 Introduction
Objectives
8.2 Introduction to polymorphism
8.3 Types of polymorphism
8.4 Function overloading
8.5 Introduction to Virtual Functions
Pure Virtual Functions
8.6 Function Overloading v/s Function Overriding
8.7 Summary
8.8 Terminal Questions
8.9 Answers
8.1 Introduction
In the previous unit you have learnt about inheritance and its types. You
have also studied in detail the concept of multiple inheritance. In this unit
you are going to study polymorphism and virtual functions. Polymorphism
refers to the ability to call different functions by using only one type of
function call. The special type of functions which can be re-defined in
derived classes are known as virtual functions. Virtual functions are special
member functions of a class which may be re-defined in the derived classes.
It is used to give specific meaning to the base class member function with
respect to the derived class. Virtual functions can be thought of as a
function name reserved in the base class which may be re-defined in the
derived classes as per the need so that every derived class has the same
function that performs specific (as redefined in the derived class) action.
Objectives:
After studying this unit you should be able to:
discuss polymorphism
explain types of polymorphism
discuss function overloading
describe virtual functions
explain pure virtual functions
compare function overloading and function overriding
Manipal University Jaipur B2114 Page No.: 179
Object Oriented Programming – C++ Unit 8
};
class truck: public vehicle
{
int passenger_load;
float payload;
public:
int passengers(void)
{
return passenger_load;
}
};
class boat: public vehicle
{
int passenger_load;
public:
int passengers(void)
{
return passenger_load;
}
void message (void) // third message
{
cout<<”Boat message, from boat, the vehicle derived class\n”;
}
};
// the main program
int main()
{
vehicle unicycle;
car sedan_car;
truck trailer;
boat sailboat;
unicycle.message();
sedan_car.message();
trailer.message();
sailboat.message();
// base and derived object assignment
unicycle = sedan_car;
unicycle.message();
// system(“pause”);
return 0;
}
The output of the program is:
Vehicle message, from vehicle, the base class
Car message, from car, the vehicle derived class
Vehicle message, from vehicle, the base class
Boat message, from boat, the vehicle derived class
Vehicle message, from vehicle, the base class
#include<iostream.h>
#include<stdlib.h>
#include<conio.h>
#define pi 3.14
class Areacalculate
{
public:
void area(int); //circle
void area(int,int); //rectangle
void area(float,int,int); //triangle
};
void Areacalculate::area(int a)
{
cout<<"Area of Circle:"<<pi*a*a;
}
void Areacalculate::area(int a,int b)
{
cout<<"Area of rectangle:"<<a*b;
}
void Areacalculate::area(float t,int a,int b)
{
cout<<"Area of triangle:"<<t*a*b;
}
void main()
{
int ch;
int a,b,r;
clrscr();
fn obj;
cout<<"\n\t\tFunction Overloading";
cout<<"\n1.Area of Circle\n2.Area of Rectangle\n3.Area of
Triangle\n4.Exit\n:”;
cout<<”Enter your Choice:”;
cin>>ch;
switch(ch)
{
case 1:
cout<<"Enter Radious of the Circle:";
cin>>r;
obj.area(r);
break;
case 2:
cout<<”Enter Sides of the Rectangle:”;
cin>>a>>b;
obj.area(a,b);
break;
case 3:
cout<<"Enter Sides of the Triangle:";
cin>>a>>b;
obj.area(0.5,a,b);
break;
case 4:
exit(0);
}
getch();
}
The output of the above program is:
Function Overloading
1. Area of Circle
2. Area of Rectangle
3. Area of Triangle
4. Exit
Enter Your Choice: 2
Enter the Sides of the Rectangle: 5 5
Area of Rectangle is: 25
1. Area of Circle
2. Area of Rectangle
3. Area of Triangle
4. Exit
Enter Your Choice: 4
# include <iostream.h>
class base
{
public:
void show()
{
cout<<“base”<<endl;
}
};
class derv1:public base
{
public:
void show()
{
cout<<“derv1”<<endl;
}
};
class derv2: public base
{
public:
void show()
{
cout<<“derv2”<<endl;
}
};
void main()
{
derv1 dv1;
derv2 dv2;
base *ptr;
ptr=&dv1;
ptr->show();
ptr=&dv2;
ptr->show();
}
}
};
void main()
{
derv1 dv1;
derv2 dv2;
base *ptr;
ptr=&dv1;
ptr->show();
ptr=&dv2;
ptr->show();
}
By declaring the base class function as virtual, we now get the output as:
derv1
derv2
As you can observe, the compiler decides which class function is to be
called during runtime depending on the contents in the pointer. This is
known as late binding or dynamic binding.
8.5.1 Pure virtual functions
Most of the times, the idea behind declaring a function (in the base class)
virtual, is to stop its execution. The base class function is used very rarely to
perform any task. Its role is only to serve as a placeholder. Then you may
question why it is required to define (in detail) virtual functions? This leads
to the idea of pure virtual functions or do-nothing functions. A pure virtual
function is virtual function with no definition. You can declare a function as
pure virtual by the following syntax:
virtual <return type> <function name> = 0;
here virtual is the keyword.
function name is the name of the function that is to be made purely virtual.
return type is the type of the data that virtual function returns.
For example: virtual void move() = 0;
Note that the function is initialized to zero. Here the assignment operator ‘=’
has nothing to do with the assignment i.e. the value zero is not assigned to
anything. It is just to inform the compiler that the function will be pure and
does not have any body.
You should note that no code is associated with this function. But what
implementation it has done on the class in which it is declared? This class
has a function, which cannot be executed. Hence, it is not possible for you
to declare any object of this class. In other words the class becomes an
abstract base class. The main objective of the abstract base class is to
provide some traits to the derived classes and to create base pointer
required for achieving run time polymorphism.
Let us see an example program:
#include <iostream,h>
class Exforsys
{
public:
virtual void example()=0; //Denotes pure virtual Function Definition
};
class Exf1:public Exforsys
{
public:
void example()
{
cout << "Welcome";
}
};
class Exf2:public Exforsys
{
public:
void example()
{
cout << "To Training";
}
};
void main()
{
Exforsys* arra[2];
Manipal University Jaipur B2114 Page No.: 191
Object Oriented Programming – C++ Unit 8
Exf1 e1;
Exf2 e2;
arra[0]=&e1;
arra[1]=&e2;
arra[0]->example();
arra[1]->example();
}
Output of the above program is:
WelcomeTo Training
In the above program example() is a pure virtual function and has no body
and it is declared with notation =0. Exf1 and Exf2 are the two derived
classes which are derived from the base class Exforsys. The pure virtual
function example() takes up new definition. A list of pointers to the base
class is defined in the main function. Here e1 and e2 are the objects of
derived classes Exf1 and EXf2.
Two objects named e1 and e2 are defined for derived classes Exf1 and
Exf2. The address of the objects e1 and e2 are stored in the array pointers
which are then used for accessing the pure virtual function example()
belonging to both the derived class EXf1 and EXf2.
Normally the virtual functions are declared in a base class and redefined in
the derived class. The base class version of the function is not always used
to perform the specific job or task, i.e. in case where the base class may be
abstract with no possibility of declaration of an object, there is no sense in
defining the virtual function in a base class. The actual function should be
implemented or defined in each of the derived class. The base class
function should just act as a placeholder to be overridden by the derived
class versions. And it is not invoked by itself directly. To be more precise, a
class having pure virtual function cannot be used to instantiate objects of its
own. Hence, there is an error in the above program.
Self Assessment Questions
8. When a function has multiple declarations of the same function name
in the same scope, it is called _________.
9. When the same function name is used in both base and derived
classes, then the base class function is declared as virtual using the
_______ keyword.
10. No code is associated with pure virtual functions. (True/ False).
8.7 Summary
Polymorphism means same content but different forms. By the concept
of polymorphism the same program code can call different functions of
different classes.
There are two levels at which polymorphism can be achieved. These
are:
o Compile time polymorphism – It is achieved through function
overloading and operator overloading and
o Run time polymorphism – This type of polymorphism is achieved
through virtual functions.
{
width = a;
height = b;
}
virtual int area()
{
cout << ”Parent class area :” <<endl;
return 0;
}
};
class Rectangle: public Shape{
public:
Rectangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape{
public:
Triangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// Main function for the program
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
return 0;
}
8. Write the ouptput of the following program:
#include<iostream.h>
class X
{
public:
void virtual display()=0; //pure virtual function
};
class Y : public X //class Y publically inherits class X
{
public:
void display()
{
cout<< “ ABC” << endl;
}
};
int main()
{
X *xptr;
X objx; //error
Y objy;
Xptr = &objy;
Xptr -> display();
return 0;
}
9. Compare function overloading and function overriding.
8.9 Answers
Self Assessment Questions
1. Polymorphism
2. True
3. Run-time, compile-time
4. Compile time
5. Run-time
6. Static or early binding
7. True
8. Function overloading
9. Virtual
10. True
Terminal Questions
1. //publish.cpp
# include <iostream.h>
#include<conio.h>
class publication
{ protected:
char title[80];
float price;
public:
virtual void getdata()
{ cout<<endl<<”enter title:”;
cin>>title;
cout<<endl<<”enter price”;
cin>>price;
}
virtual void putdata()
{
cout<< endl<<”Title”<<title;
cout<<endl<<”Price”<<price;
}
};
class book: public publication
{
private:
int pages;
public:
void getdata()
{ publication::getdata();
cout<<endl<<”enter number of pages”;
cin>>pages;
}
void putdata()
{
publication::putdata();
cout<< endl<<”Number of pages”<<pages;
}
};
class cdrom: public publication
{
private:
float time;
public:
void getdata()
{ publication::getdata();
cout<<endl<<”enter playing time:”;
cin>>time;
}
void putdata()
{
publication::putdata();
cout<< endl<<”Playing time”<<time;
}
};
void main()
{
publication * ptr[10];
book* bptr;
cdrom* cptr;
char ch;
int n=0;
do
Manipal University Jaipur B2114 Page No.: 198
Object Oriented Programming – C++ Unit 8
{
cout<<”Enter data for book or cdrom(b/c)”;
cin>>ch;
if (ch==’b’)
{
bptr= new book;
bptr->getdata();
ptr[n++]=bptr;
}
else
{cptr=new cdrom;
cptr->getdata();
ptr[n++]=cptr;
}
cout<<” enter another (y/n)”;
cin>>ch;
}while (ch==’y’);
for(int j=0;j<n;j++)
ptr[j]->putdata();
getch();
}.
2. Polymorphism means the same content but different forms. The origin of
the word polymorphism comes from two Greek words’ poly (many) and
morphos (form), together meaning multiform. In C++, by the concept of
polymorphism the same program code can call different functions of
different classes. Refer section 8.2 for more details.
3. There are two levels at which polymorphism can be achieved. These
are:
Compile time polymorphism - It is achieved through function overloading
and operator overloading Run-time polymorphism – This type of
polymorphism is achieved through virtual functions. Refer section 8.3
for more details.
4. In C++ when a function has multiple declarations of the same function
name in the same scope, it is called function overloading. These
declarations differ in the type and number of arguments in the argument
list. Refer section 8.4 for more details.
References:
Oriented Programming With C++, by Subhash K U. Pearson Education
India.
Data Structures and Algorithms, first edition, by A. A. Puntambekar.
Technical Publications.
9.1 Introduction
In the previous unit you studied about polymorphism and its types. You also
studied about function overloading and its types. In this unit you are going to
learn the ways to handle files in C++ and to process input and output
operations, and get an idea of preprocessor directives in C++. You are also
going to study the procedure to pass arguments from command line prompt.
You are already using files to store your program. The files can also be
used to store input for a program or to receive output from a program.
These files used for program input-output are the same files that you used
to store your programs. The file streams allow you to write programs that
handle file and keyboard inputs as well as file and screen outputs in a
unified way. In C++, fstream class is used to perform file processing. Unlike
the FILE structure, fstream is a complete C++ class with constructors, a
destructor and overloaded operators. To perform file processing, you can
declare an instance of an fstream object. If you do not yet know the name of
the file you want to process, you can use the default constructor.
Objectives:
After studying this unit, you should be able to:
explain the way file input-output is handled in C++
describe the read-and-write operation of string content to a file
describe the methods to transfer output to printer
discuss preprocessor directives
As you can see in figure 9.1, all the stream classes are inherited from the
ios class. It provides support for formatted and unformatted I/O operations.
It contains many constants and member functions that can be used by all
other input and output classes. All constants and functions that are
necessary for handling input and output operations are present in this ios
class. istream (input stream) class is derived from ios class, and all the
necessary functions for input handling are present in it. It provides facilities
for formatted and unformatted input. Besides, it contains pointer to a buffer
object, i.e. streambuf object. Some functions that are defined in this class
are get(), getline(), read() and overload extraction operators (>>).
ostream (output stream) class is also derived from ios class, and performs
all types of output related functions like put(), write(). It provides facilities for
formatted output. The overload insertion operator (<<) is defined in this
class.
iostream (input/output) stream class inherits the properties of istream and
ostream class through multiple inheritance, and hence, contains all the input
and output functions.
streambuf class provides the interface to physical devices through buffers.
Three classes - istream_withassign, ostream_withassign, iostream with
assign are inherited from istream, ostream, iostream respectively, which add
assignment operators to these classes. cout is a predefined object of the
ostream_withassign class. cin is an object of the istream_withassign class.
The ifstream class is used for input files and it is inherited from classes
istream and fstreambase. Similarly, class ostream is used for output files,
and is derived from classes- ostream and fstreambase. Files used for both
input output operations are inherited from the class - fstream. The class
fstream is inherited from both iostream and fstreambase. The classes
fstream, ifstream and ofstream are declared in the fstream.h header file.
The file fstream.h also includes iostream.h, so the programs using fstream.h
need not explicitly include iostream.h.
Self Assessment Questions
1. cin is a predefined object of _____________ class.
2. cout is a predefined object of ____________ class.
3. All the stream classes are inherited from _________class.
outfile<<“Welcome\n”;
outfile<<“See you\n”;
}
You need to create an object of ifstream class to read data from file. To read
the data from the file, you have to use the function ‘get()’ or ‘getline()’. The
‘get()’ function also reads one character at a time. The following is the
syntax of the ‘get()’ function.
objectname.get(character variable)
Here the objectname is an object of ifstream class and the character to be
read from the file is stored in a variable.
The following is the program to show how to read character from file. The
program shown below reads the contents of the file character by character,
and displays the character on computer screen.
#include<fstream.h>
#include <conio.h>
void main()
{
ifstream infile("test.txt");
char ch;
clrscr();
while (infile) // infile becomes 0 when eof condition is reached
{infile.get(ch);
cout << ch;}
getch();}
You can observe in the above program that the end of file (eof) condition is
checked using the object name. You can also use eof() function to check
this condition. The eof() function returns non-zero value when an end of file
is encountered, and returns zero when reading the file.
The getline() function is also used to read contents from a file. But unlike
get() function it reads the contents line by line. The program below shows
the use of getline function.
#include<fstream.h>
#include <conio.h>
void main()
{
ifstream infile("test.txt");
char buffer[80];
clrscr();
while (!infile.eof()) //returns nonzero value when eof condition is reached
{infile.getline(buffer,80);
cout << buffer;}
getch();}
The extraction operator (>>) can be used with ifstream object to read the
text as this operator is overloaded in the istream class. (ifstream is derived
from istream). However, it reads one word at a time. The following program
shows the same:
#include<fstream.h>
#include <conio.h>
void main()
{
ifstream infile("test.txt");
char buffer[25];
clrscr();
while (infile) //infile becomes 0 when eof condition is reached
{infile>>buffer;
cout << buffer;
}
getch();
}
In these programs, while reading contents from the file, we have presumed
that the files are existing on the disk. But it would be a good practice if you
apply a check to find whether the file to be read exists on the disk or not.
Many such status checks are contained in ios class. In the program shown
below, the check applied reports an error if the file doesn’t exist.
#include<fstream.h>
#include <conio.h>
void main()
{
ifstream infile("test.txt");
if (!infile) // check for error while opening the file
cout<<”Cannot open file”;
else
{
char buffer[25];
clrscr();
while (infile) //infile becomes 0 when eof condition is reached
{infile>>buffer;
cout << buffer;}
}
getch();}
version of main doesn’t take any arguments. But many a time, programs
need some kind of input to work with. For example, you are writing a code to
count the number of words in a text file.
The user has to have some way of telling the program which file to open. To
do this, you may take this approach:
int main()
{
using namespace std;
cout << "Enter the name of the file: ";
char strFilename[255];
cin >> strFilename; // open file and process it
}
The major problem associated with this approach is that every time the file
runs, the program waits for the user to enter the input. It indicates that
execution of the program cannot be automated easily. For example, if you
want to execute this program on 600 files per week, then the program will
not proceed. Instead, it will wait until you enter the name of the file every
time it is executed.
Command line arguments
For programs that have minimal and/or optional inputs, command line
arguments offer a great way to make programs more modular. The optional
string arguments that are given by the user to a program during execution
are known as ‘command line arguments’. The operating system passes
these arguments to the program, and the program uses them as input.
Programs are normally run by invoking them by name. To run a program
you have to type the name of the program on the command line. For
example, to run the executable file “WordCount” that is located in the root
directory of the C:\ drive on a Windows machine, you could type:
C:\\>WordCount
To pass the command line arguments to the program ‘WordCount’, you
have to list the command line arguments after the executable name. The
example is shown below:
C:\\>WordCount Myfile.txt
You can see in the above statement that when the program named
‘WordCount’ is executed, Myfile.txt will be passed to it as a command line
argument. It is possible for a program to have a number of command line
arguments. For example:
C:\\>WordCount Myfile.txt Myotherfile.txt
This also works for other command line operating systems, such as Linux
(though your prompt and directory structure will undoubtedly vary).
If a program is run from an IDE (Integrated Development Environment) then
some way should be provided by IDE to enter command line arguments. For
example, in Microsoft Visual Studio 2005, right click on your project in the
solution explorer, and then choose properties. Open the “Configuration
Properties” tree element, and choose “Debugging”. In the right pane, there
is a line called “Command Arguments”. You can enter your command line
arguments there for testing, and they will be automatically passed to your
program when you run it.
Now you have already studied the way to provide command line arguments
to a program. The next thing you have to study is to access them from
within our C++ program. To achieve this task, we use some other form of
the main program that we have used in our programs till now. We have to
pass two arguments in the main function i.e. argc and argv. The names of
the arguments are by convention. The example is as follows:
int main(int argc, char *argv[])
argc is an argument containing the number of arguments passed to the
program. argc will always be at least 1, because the first argument is always
the name of the program itself! The value of argc will be incremented by 1
each time the user provides the command line argument. Each command
line argument the user provides will cause argc to increase by 1.
The actual arguments are stored in argv. Although the declaration of argv
looks intimidating, argv is really just an array of C-style strings. The length of
this array is argc. Let’s write a short program to print the value of all the
command line parameters:
#include <iostream>
int main(int argc, char *argv[])
{
using namespace std;
cout << "There are " << argc << " arguments:" << endl;
// Loop through each argument and print its number and value
for (int nArg=0; nArg < argc; nArg++)
cout << nArg << " " << argv[nArg] << endl;
return 0;
}
contents to display screen or printer or disk file, the syntax remains the
same. That is the beauty of stream class organization hierarchy.
Self Assessment Questions
9. The optional string arguments that are given by the user to a program
during execution are known as ____________.
10. _______ variable contains the number of arguments passed to the
program.
11. _______ variable contains the actual arguments passed to the program.
Now let us preprocess this code to see the result, assuming that we have
the source code file. We will compile this file with –E option and save the
result in result.p file. Now, if you check the result.p file, you will see that it
has lots of information, and at the bottom of the file, you will find the value
replaced as follows:
$gcc -E test.cpp > test.p
int main ()
{
cout << "Value of PI :" << 3.14159 << endl;
return 0;
}
Function-Like Macros
You can use #define to define a macro which will take argument as follows:
#include <iostream.h>
#define MIN(a,b) ( ((a)<(b)) ? a : b)
int main ()
{
int i, j;
i = 100;
j = 30;
cout <<"The minimum is " << MIN(i, j) << endl;
return 0;
}
The output of the above program will be:
The minimum is 30
9.5.2 Conditional Compilation
C++ provides the facility to compile the selective portions of our program’s
source code. This can be performed by using some directives. This
procedure is known as conditional compilation.
The conditional preprocessor construct is much like the if selection structure.
Consider the following preprocessor code:
#ifndef NULL
#define NULL 0
#endif
You can compile a program for debugging purpose, and can turn
‘debugging’ on or off using a single macro as follows:
#ifdef DEBUG
cerr <<"Variable x = " << x << endl;
#endif
This causes the cerr statement to be compiled in the program if the
symbolic constant DEBUG has been defined before directive #ifdef DEBUG.
You can use #if 0 statement to comment out a portion of the program as
follows:
#if 0
code prevented from compiling
#endif
The following example illustrates the above concept:
#include <iostream.h>
#define DEBUG
#define MIN(a,b) (((a)<(b)) ? a : b)
int main ()
{
int i, j;
i = 100;
j = 30;
#ifdef DEBUG
cerr <<"Trace: Inside main function" << endl;
#endif
#if 0
/* This is commented part */
cout << MKSTR(HELLO C++) << endl;
#endif
cout <<"The minimum is " << MIN(i, j) << endl;
#ifdef DEBUG
cerr <<"Trace: Coming out of main function" << endl;
#endif
return 0;
}
The output of the above program will be:
Trace: Inside main function
The minimum is 30
Trace: Coming out of main function
9.5.3 Predefined C++ Macros
C++ provides a number of predefined macros. Table 9.1 shows the
predefined macros provided by C++.
Table 9.1: Predefined macros
Macro Description
An integer that gives the current line number of the program when
_LINE__
it is being compiled.
A string that gives the current file name of the program when it is
__FILE__
being compiled.
This contains a string of the form month/day/year that is the date
__DATE__
of the translation of the source file into object code.
This contains a string of the form ‘hour:minute:second’ that is the
__TIME__
time at which the program was compiled.
9.6 Summary
A stream is a flow of characters. If the flow is into your program then it is
called input stream, and if the flow is out of your program then it is called
output stream.
The stream classes are organized in a hierarchical manner.
ofstram class is used to write characters to a file.
If stream class is used to read data from a file.
The optional string arguments that are given during execution by the user
to a program are known as command line arguments.
argc is an interger type argument containing the number of arguments
passed to the program. argv contains the actual arguments passed to the
program.
There are some instructions given to the compiler to preprocess the
information before actual compilation begins. These instructions are
known as preprocessor directives. All preprocessor directives begin with
#, and only white-space characters may appear before a preprocessor
directive on a line.
The symbolic constants are created by #define directive. These symbolic
constants are known as macros.
9.8 Answers
Self Assessment Questions
1. istream_withassign
2. ostream_withassign
3. ios
4. ofstream
5. ifstream
6. one
7. getline()
8. eof()
9. command line arguments
10. argc
11. argv
12. Preprocessor directives
13. True
14. __FILE__
Terminal Questions
1. //file2prn.cpp
# include<fstream.h>
void main()
{
char ch;
ifstream infile;
infile.open("sample.txt");
ofstream outfile;
outfile.open("PRN");
while(infile.get(ch))
{ outfile.put(ch);
}
}
2. //mytype.cpp
# include<fstream.h>
# include<process.h>
void main(int argc, char* argv[])
{ if (argc!=2)
{ cerr<<“\nFormat: mytype filename”;
exit(-1);
}
char ch;
ifstream infile;
infile.open(arg[1]);
if (!infile)
{ cerr<<“cannot open”<<argv[1];
exit(-1);
}
while(infile)
{infile.get(ch);
cout<<ch;}
}
References:
Object Oriented Programming with C++ - Sixth Edition, by
E Balagurusamy. Tata McGraw-Hill Education.
Problem Solving with C++, 6/e, By Savitch, Pearson Education India.
C++ for Engineers and Scientists, By Gary Bronson, Cengage Learning.
http://enggedu.com/
http://www.tutorialspoint.com
10.1 Introduction
In the previous unit you studied about files, streams, command line
arguments and preprocessor directives. In this unit you are going to study
I/O stream hierarchy and simple programs using these streams. You are
also going to learn the methods to format the output of the programs
In C++, I/O is done with "streams." An input stream such as cin is a source
of data that can be read into variables. An output stream such as cout is a
place where data can be sent for display, storage, or communication. A file
is a collection of data saved on a disk drive. Data in a file differs from data in
variables because a file can exist before the program is run and can persist
after the program ends. To read data from a file or to save data in a file, a
program just has to use the right type of stream.
Objectives:
After studying this unit you should be able to:
explain C++ iostream library and its organization
describe programming using I/O streams
same name as their char type instantiations but they have the prefix
basic in their names. For example, the class template which istream is
instantiated from is called basic_istream, the one from which fstream is
instantiated is called basic_fstream, and so on. The ios_base is an
exception which is by itself is type-independent.
Class template instantiations – The library contains two standard sets
of instantiations of the complete iostream class template hierarchy i.e.
narrow oriented which manipulates the elements of char type and wide
oriented that manipulates the wchar_t type elements. The few narrow
oriented classes are ios, istream and ofstream. The names of narrow
oriented classes and relationship amongst them is shown in figure 10.1.
The wide oriented instantiation classes has the same naming
convention as narrow oriented instantiation only difference is that in
wide oriented instantiation the name of classes and objects are prefixed
with character ‘w’. For example wios, wistream, wostream.
Standard objects – Many objects that performs standard input and
output operations are declared in <iostream> library. These are of two
types i.e. narrow oriented objects and wide oriented objects. Example of
narrow oriented objects are – cin, cout, cerr and clog. And wide oriented
objects are declared as win, wout, wcerr and wclog.
Types – The iostream classes barely use fundamental types on their
member's prototypes. They generally use defined types that depend on
the traits used in their instantiation. For the default char and wchar_t
instantiations, types - streampos, streamoff and streamsize are used to
represent positions, offsets and sizes, respectively.
Manipulators – The global functions that are used in conjunction with
insertion (<<) and extraction (>>) operators performed on iostream
objects are known as manipulators. The formatting settings and
properties of streams are modified by manipulators. Examples of
manipulators are- endl, hex and scientific.
10.2.2 Organization
The library and its hierarchy of classes are split in different files:
As you have observed in the programs that we don’t include <ios>,
<istream>, <ostream>, <streambuf> and <iosfwd> files directly in the
programs. They describe the base classes of the hierarchy and are
automatically included by other header files of the library that contain
derived classes.
<iostream> It contains the declarations of the objects that
performstandard input and output operations(including cin and cout).
<fstream> the file stream classes (like the template basic_ifstream or
the class ofstream) as well as the internal buffer objects used with these
(basic_filebuf) are defined in this file. These classes manipulate the files
using streams.
<sstream>: The classes which are defined in file manipulates string
objects as if they were streams.
<iomanip> Declares some standard manipulators with parameters to be
used with extraction and insertion operators to modify internal flags and
formatting options.
10.2.3 Elements of the iostream Library
Classes
Objects
Cin Standard input stream
Cout Standard output stream
Cerr Standard output stream for errors
Clog Standard output stream for logging
Types
Fpos Stream position class template
Streamoff Stream offset type
Streampos Stream position type
Streamsize Stream size type
Manipulators
Boolalpha Alphanumerical bool values
Dec Use decimal base
Endl Insert newline and flush
Ends Insert null character
Fixed Use fixed-point notation
Flush Flush stream buffer
Hex Use hexadecimal base
Internal Adjust field by inserting characters at an internal
position
Left Adjust output to the left
Noboolalpha No alphanumerical bool values
Noshowbase Do not show numerical base prefixes
Noshowpoint Do not show decimal point
Noshowpos Do not show positive signs
Noskipws Do not skip whitespaces
Nounitbuf Do not force flushes after insertions
Nouppercase Do not generate upper case letters
Oct Use octal base
Resetiosflags Reset format flags
Right Adjust output to the right
Scientific Use scientific notation
Setbase Set basefield flag
Setfill Set fill character
Creating Streams
The streams need to be created before they are used in the programs. The
statements to create streams are similar to the variable declaration. These
statements are written at the top of the program with variable declaration.
The example to create a stream is shown below:
ifstream in_stream;
ofstream out_stream;
Before we can use an input or output stream in a program, we must create
it. Statements to create streams look like variable declarations, and are
usually placed at the top of programs or function implementations along with
the variable declarations. So for example the statements
ifstream in_stream; This statement creates a stream called "in_stream"
belonging to the class (like type) "ifstream" (input-file-stream).
ofstream out_stream;- This statement creates a stream called "out_stream"
belonging to the class "ofstream" (output-file-stream).
However, the analogy between streams and ordinary variables (of type "int",
"char", etc.) can't be taken too far. We cannot, for example, use simple
assignment statements with streams (e.g. we can't just write "in_stream1 =
in_stream2").
Connecting and Disconnecting Streams to Files
Consider that a file named “test.txt” exists shown in figure 10.2. The
diagrammatic representation of this file is shown below:
The statement:
out_stream.close();
has a similar effect, but in addition, the system will "clean up" by adding an
"end-of-file" marker at the end of the file. Thus, if no data has been output to
"Test.txt" since "out_stream" was connected to it, we change from the
situation in Figure 10.4 to figure 10.6.
(program)
You should already know what the first line is. Hence, we shall move to next
important statement.
ifstream OpenFile(“cpp-home.txt”);
ifstream means “input file stream”. In the previous program, it was ofstream,
which means “output file stream”. The previous program is to write a file,
that’s why it was “output”. But this program is to read from a file, that’s why it
is “input”. OpenFile is the object from class ifstream, which will handle the
input file stream. And in the inverted commas, is the name of the file to
open.
Note that there is nothing to check whether the file exists. This will be
covered in a short while.
char ch;
An explanation for this statement is redundant.
while(!OpenFile.eof())
As you have already studied, when the end of the file is encountered then
the function eof() returns a non-zero value. So we use a while loop that will
run until the end of file is encountered. So, we will get through the whole file,
so that we can read it.
OpenFile.get(ch);
OpenFile is the object from class ifstream. This class contains the get()
function. So, as long as we have an object we can use this function. The
get() function extracts a single character from the stream and returns it. In
the program shown above the get() function takes the variable name as
parameter in which the character which is read is placed. So, after calling
OpenFile.get(ch) it will read one character from the stream OpenFile, and
will put this character into the variable ch. This function if called second time
will read the next character. It will not read the same character again and
every time we loop, we read one character and put it into ch.
cout << ch;
Explanation for this statement is redundant.
OpenFile.close();
As we have opened the file stream, we need to close it. Use the close()
function, to close it. Just as in the previous program.
Manipal University Jaipur B2114 Page No.: 231
Object Oriented Programming – C++ Unit 10
When you compile and run this program, the output will be:
Hello World, from www.cpp-home.com and Loobian!
Self Assessment Questions
5. A_________ is a stream or array of uninterpreted bytes.
6. The statements to create streams are written at the top of the program
with variable declaration. (True/False).
7. The statement ifstream in_stream; creates a stream called "in_stream"
belonging to the class "ifstream". (True/False).
The special functions that can be included in I/O statements to alter the
format parameters of a stream are known as manipulators. Table 10.2
shows some of important manipulator functions that are used frequently.
The header file iomapin should be included in the program to access these
manipulators.
The value 543 is printed right-justified in the first five columns. The
specification width(5) does not retain the setting for printing the number
12. This can be improved as follows:
cout.width(5);
cout<<543;
cout.width(5);
cout<<12<<”\n”;
The result of the above statement will be:
5 4 3 1 2
This kind of padding is used in the financial institutions like banks while
printing cheques so that one can change the amount easily.
4. Formatting Flags, Bit-fields and self()
You have studied that when the function width is used, the value is
printed right-justified by default in the field width created. But usually we
print the text left-justified. The self() function of ios class is used to
perform this task. The self function can be used as follows:
cout.self(arg1, arg2);
The arg1 is the formatting flags defined in the ios class. The formatting
flag specifies the format action required for the output. Another ios
constant, arg2, known as bit field specifies the group to which the
formatting flag belongs. The table 10.3 shows the bit fields, flags and
their format actions. There are three bit fields and each has a group of
format flags which are mutually exclusive. Examples:
cout.self(ios::left, ios::adjustfield);
cout.self(ios::scientific, ios::floatfield);
It should be noted that the first argument should be one of the group
members of the second argument.
This statement will print the trailing zeros and trailing decimal points.
Under default precision, the value 3.25 will be displayed as 3.250000 as
the default precision assumes a precision of six digits.
Similarly, we can print a plus sign before a positive nume3 using the
following statement:
cout.self(ios::showpos); //show + sign
For example consider the following statements:
cout.self(ios::showpint);
cout.self(ios::showpos);
cout.precision(3);
cout.slef(ios::fixed, ios::floatfield);
cout.self(ios::internal, ios::adjustfield);
cout.width(10);
cout<<275.5<<”\n”;
The output of the above statements will be:
+ 2 7 5 . 5 0 0
10.5 Summary
A stream is a sequence of bytes. It is a continuous flow of data elements
that are transmitted or intended for transmission in a defined format. It
works either as a source from where the data can be obtained or as a
destination for the output sent.
To operate with streams we have to our disposal the standard iostream
library which provides us the following elements: Basic class templates,
Class template instantiations, Standard objects, Types, Manipulators.
In C++, the file stream classes are designed with the idea that a file
should simply be viewed as a stream or array of uninterpreted bytes.
The current reading position, which is the index of the next byte that will
be read from the file.
The current writing position, which is the index of the byte location where
the next output byte will be placed.
The streams need to be created before they are used in the programs.
The statements to create streams are similar to the variable declaration.
The streams need to be created before they are used in the programs.
The statements to create streams are similar to the variable declaration.
These statements are written at the top of the program with variable
declaration.
C++ provides various console I/O functions for formatting the outputs.
Formatting means displaying the outputs in more readable and
10.7 Answers
Self Assessment Questions
1. Iostream
2. Stream
3. Class templates
4. Standard output stream for logging
5. File
6. True
7. True
8. using ios class functions, flags and manipulators
9. width()
10. manipulators , iomapin
11. fill()
12. True
Terminal Questions
1. A stream is sequence of bytes. It is a continuous flow of data elements
that are transmitted or intended for transmission in a defined format. It
works either as a source from where the data can be obtained or as a
destination for the output sent. For more details refer section 10.2.
2. Classes, objects and types are the major division under elements of
iostream library. For more details refer section 10.2.
3. In C++, the file stream classes are designed with the idea that a file
should simply be viewed as a stream or array of uninterpreted bytes. For
more details refer section 10.3.
4. The first program, will create a file, and put some text into it.
#include <fstream>
using namespace std;
int main() {
ofstream SaveFile("cpp-home.txt");
SaveFile << "Hello World, from www.cpp-home.com and Loobian!";
SaveFile.close();
return 0;
}
The above program will create cpp-home.txt file and will write the
sentence -Hello World, from www.cpp-home.com and Loobian into it.
For more details refer section 10.3.2.
5. The ios class contains many member functions that would help us to
format the output in a number of ways. The important ios class format
functions are as follows: width(), precision(), fill(), self(), unself(). For
more details refer section 10.4.1.
6. Manipulators are the functions which are used to manipulate the output
formats and are provided in header file iomapin. They provide the same
features as that of the ios member functions and flags.
For more details refer section 10.4.2.
Unit 11 Files
Structure:
11.1 Introduction
Objectives
11.2 Managing I/O Streams
Opening and closing a file
Checking for Failures with File Commands
11.3 Checking the I/O Status - Flags
11.4 Dealing with Binary Files
11.5 Some Useful Functions
11.6 Summary
11.7 Terminal Questions
11.8 Answers
11.1 Introduction
In the previous unit, you studied iostream hierarchy, standard IO stream
library and its organization. You also studied the methods to format the
output of the programs. In this unit you are going to study different methods
of opening and closing a file, methods to check I/O status. You will also
learn to deal with binary files. In C++, the file stream classes are designed
with the idea that a file should simply be viewed as a stream or an array of
uninterrupted bytes. For convenience, the "array" of bytes stored in a file is
indexed from zero to len-1, where len is the total number of bytes in the
entire file. You can open a file stream object if you can supply a file name
along with an I/O mode parameter to the constructor when declaring an
object. Binary file is a file of any length that holds bytes with values in the
range 0 to 0xff (0 to 255). These bytes have no other meaning.
Objectives:
After studying this unit, you should be able to:
describe opening and closing of files in different modes
describe the ways to check the I/O status
explain binary files
discuss the important functions pertaining to files
You can also use the same file for reading and writing the data as shown in
the example below:
Program1
…………..
………….
ofstream outfile(“salary”); // the outfile is created and “salary’ is
connected to it
…………..
………….
Program2
…………..
………….
ifstream infile(“salary”); //infile is created and ‘salary” is
connected to
it.
When the stream object expires, then connection with the first file is closed
automatically. As you can observe from the above statements, when
program1 terminates, the salary file is disconnected from the outfile stream.
When the program2 is terminated a similar action is taken.
We can use one program instead of two programs (one for writing data and
another for reading data). For example:
………….
………….
outfile.close(); //disconnects salary from outfile and connects
to infile
ifstream infile(“salary”);
…………
…………
infile.close(); //disconnect salary form infile
You can observe that even though one program is used, two filestream
objects are created. One is an outfile to put data to the file, and another, an
infile to get data from the file. The statement outfile.close(); disconnects the
file from the output stream outfile. Note that the object outfile continues to
exist, and later the salary file can again be connected to outfile or to any
other stream. In the example shown above we have connected the salary
file to the infile stream to read data.
The program below uses a single file for both writing and reading the data.
First it takes data from the keyboard, and writes it to the file. The file is
closed once the writing is completed. The program again opens the same
file, reads the information present in the file and displays it on the screen.
// Program to create file with single constructor
#include<iostream.h>
#include<fstream.h>
int main()
{
ofstream outf(“ file1”); //connects ifile1 to outf
cout<< “Enter item name:”;
char name[30]; //get name from keyboard and write it to file
named file1
cin>> name;
outf << name << “\n”;
cout << “Enter item cost:”;
float cost;
cin>> cost; // input the value of cost
outf << cost << “\n”; //write to file file1
outf.close(); //disconnect file named file1 from outf
ifstream inf(“file1”); // connect file named file1 to inf
inf >> name; // read name from file1
inf >> cost; // read cost from file named file1
cout << “\n”;
cout << “Item name:” << name << “\n”;
cout << Item cost :” << cost << “\n”;
inf.close(); //disconnect file named file1 from inf
return 0;
}
The output of the above program will be:
Enter item name: Book
Enter item cost: 200
Item name: Book
Item cost: 200
Manipal University Jaipur B2114 Page No.: 245
Object Oriented Programming – C++ Unit 11
In fact, all these values are int constants from an enumerated type. But, for
making your life easier, you can use them as you see them in the table.
Here is an example for the method to use the open modes:
#include <fstream.h>
void main() {
ofstream SaveFile("file1.txt", ios::ate);
SaveFile << "That's new!\n";
SaveFile.close();
}
As you see in the table, using ios::ate writes at the end of the file. If it wasn’t
used, the file would have been overwritten. So, if file1.txt has this text:
Hi! This is test from www.cpp-home.com!
running it will add “That’s new!” to it; so it will look this way:
Hi! This is test from www.cpp-home.com! That’s new!
If you want to set more than one open mode, just use the OR operator (|)
this way:
ios::ate | ios::binary
Using different open modes helps make file handling an easy job. Having
the liberty to choose a combination of these, in the same way, comes very
handy in using streams effectively, and to the requirements of the project.
Moving on to something more intriguing and important, we can create a file
stream handle, which you can use to read/write file at the same time. Here
is how it works:
fstream File(“cpp-home.txt”, ios::in | ios::out);
In fact, that is only the declaration. The code line above creates a file stream
handle, named File. As you know, this is an object from class fstream.
When using fstream, you should specify ios::in and ios::out as open modes.
This way, you can read from the file, and write in it, at the same time,
without creating new file handles. Well, of course, you can only read or
write. Here is the code example:
#include <fstream.h>
void main()
{
fstream File("test.txt", ios::in | ios::out);
File << "Hi!"; //put “Hi!” in the file
static char str[10]; //when using static, the array is automatically
//initialized, and very cell NULLed
File.seekg(ios::beg); //get back to the beginning of the file
//this function is explained a bit later
File >> str;
cout << str << endl;
File.close();
}
Let us now understand the above program:
fstream File(“test.txt”, ios::in | ios::out);
This line, creates an object from class fstream. At the time of execution, the
program opens the file test.txt in read/write mode. This means that you can
read from the file and put data into it at the same time.
File << “Hi!”;
This statement writes Hi! in the file named test.txt
static char str[10];
This makes a char array with 10 cells. The word static initializes the array
when at the time of creation.
File.seekg(ios::beg);
To understand this statement, consider the following statement:
while(!OpenFile.eof()) // here OpenFile is a stream-object
{
OpenFile.get(ch);
cout << ch;
}
This is ‘a while loop’ that will loop until you reach the end of the file. But how
does the loop know if the end of the file is reached? The answer is; when
you read the file, there is something like an inside-pointer (current
reading/writing position) that shows where you are, with the reading (and
writing, too). Every time you call OpenFile.get(ch), it returns the current
Using File >> str, will put just “Hi!” to the str array. And, as what we put in
the file was “Hi!” we don’t need to use a while loop, that takes more time to
code. That’s why this technique was used. By the way, in the while loop for
reading that has been used so far, the program reads the file, character by
character. But you can read it word by word, this way:
char str[30]; //the word can’t be more than 30 characters long
while(!OpenFile.eof())
{
OpenFile >> str;
cout << str;
}
You can also read it line by line, this way:
char line[100]; //a whole line will be stored here
while(!OpenFile.eof())
{
OpenFile.getline(line,100); //where 100 is the size of the array
cout << line << endl;
}
It is recommended that you use the line-by-line one, or the first technique
that was mentioned, i.e., the one which reads char-by-char. The one that
reads word-by-word is not a good option since it will not read the new line.
So if you have a new line in the file, it will not display it as a new line, but will
append the text to the existing one. But using getline() or get() will show you
the file just as it is.
11.2.2 Checking for Failure with File Commands
Now, we will see how to check whether the file opening was successful or
not. In fact, there are a few good ways to check it thus, and we will learn
some of them. Notice that where there is X, it can be either “o”, or “i”, or
nothing (it will then be fstream object).
Example 1: The most usual way
Xfstream File(“cpp-home.txt”);
if (!File)
{
cout << “Error opening the file! Aborting…\n”;
exit(1);
}
Example 2: If the file is created, return an error
ofstream File("unexisting.txt", ios::nocreate);
if(!File)
{
cout << “Error opening the file! Aborting…\n”;
exit(1);
}
Example 3: Using the fail() function
ofstream File("filer.txt", ios::nocreate);
if(File.fail())
{
cout << “Error opening the file! Aborting…\n”;
exit(1);
}
You can see a function fail() in the above example. A non-zero value is
retuned by this function if any I/O occurs. There is an interesting fact that
needs to be mentioned here. Say, you have created a file stream, but you
have not opened a file, as in the following way:
ifstream File; //it could also be ofstream
This way, we have a handle, but we still have not opened the file. If you
want to open it later, it can be done with the open() function (which has
already been covered in this chapter). But if anywhere in your program, you
need to know whether currently there is an opened file, you can check it
with the function is_open(). It retunrs 0 (false) if the file is not opened, and 1
(true) if there is an opened file. For example:
ofstream File1;
File1.open("file1.txt");
cout << File1.is_open() << endl;
The code above, will return 1 as we open a file (on line 2). But the code
below will return 0, because we do not open a file, but just create a file
stream handle:
ofstream File1;
cout << File1.is_open() << endl;
There are two ways to receive information about the I/O status. One of them
is by calling the function rdstate() which is a member of ios. It returns the
current status of the error-flags (the above mentioned). For example, the
goodbit is returned by the function rdstate() if no errors are encountered.
The other way to check the I/O status is by using any of the following
functions:
bool bad();
bool eof(); //Read until the end of the file has been reached
bool fail(); / /Check if the file opening was successful
bool good();
The function bad() returns true, if the badbit is set. The fail() function returns
true if the failbit is set. The good() function returns true if there are no errors
(the goodbit bit is set). And the eof() function returns true if the end of the
file has been reached (the eofbit is set.).
if (Test.rdstate() == ios::eofbit)
cout << "EOF!\n";
Test.close();
}
Self Assessment Questions
5. The function bad() returns true, if the badbit flag is set. (True/False).
6. ______________ function returns the current status of the error-flags.
input stream, but it can be set to stop reading if it met a certain symbol.
Here is how you should pass the parameters to it:
getline(array, array_size, delim);
And here is a code example:
#include <fstream.h>
void main() {
//if we have "Hello World" in test_file.txt
Ifstream File("test_file.txt");
static char arr[10];
/*read, until one of these happens:
1) You have read 10
2) You met the letter "o"
3) There is a new line
*/
File.getline(arr, 10, 'o');
cout << arr << endl; //it should display "Hell"
File.close();
}
peek() – This function will return the next character from an input file
stream, but unlike get() function, it won’t move the inside-pointer. get(),
for example, returns the next character in the stream, and after that, it
moves the inside-pointer, so that the next time you call the get()
function, it will return the next character, but not the same one. Using
peek() will return a character, but it won’t move the cursor. So, if you call
the peek() function twice in succession, it will return the same character.
The syntax to use the peek() function is as follows:
stream_obj.peek();
In the above syntax peek() function will return the next character or eof if
the end of the file is reached.
Consider the following code example:
#include <fstream.h>
void main()
{
//if we have "Hello World" in test_file.txt
ifstream File("test_file.txt");
char ch;
Manipal University Jaipur B2114 Page No.: 259
Object Oriented Programming – C++ Unit 11
File.get(ch);
cout << ch << endl; //should display "H"
cout << char(File.peek()) << endl; //should display "e"
cout << char(File.peek()) << endl; //should display "e" again
File.get(ch);
cout << ch << endl; //should display "e" again
File.close();
}
The peek() function actually returns the ASCII code of the char, but not
the char itself. So, if you want to see the character itself, you have to call
it the way shown above.
remove()
The files can be removed by calling the remove function which has the
following specification:
#include<stdio.h>
int remove(const char *filename);
The remove() function deletes a file whose name is the string pointed to
by fname. If successful, it returns zero, or else, it returns a non-zero
value. If fname is open, i.e. if it is associated with a stream and this
association has not been broken, then the behavior of remove is not
defined.
Let us see the following example:
/* remove example: remove myfile.txt */
#include <stdio.h>
int main ()
{
if( remove( "myfile.txt" ) != 0 )
perror( "Error deleting file" );
else
puts( "File successfully deleted" );
return 0;
}
If the file myfile.txt exists before the execution and the program has write
access to it, the file would be deleted and the following message would
be displayed to stdout:
11.6 Summary
This unit focusses on how to manage the file to operate using I/O
streams. This chapter has discussed comprehensively the C++ streams.
Various examples provided throughout this chapter illustrate the use of
these streams.
For opening a file you have to create a file stream, and it is to be linked
to a filename. You can define a filename using ifstream, ofstream and
fstream classes. These classes are contained in the header file fstream.
There are two ways to open a file. They are: using the constructor
function of the class, and using the member function open() of the class.
The open() function is used to open multiple files that use the same
stream object.
There are two ways to receive information about the I/O status. One of
them is by calling the function rdstate(). And the other way to check the
I/O status is by using any of the following functions: bool bad(), bool
eof(), bool fail() and bool good().
The functions that give you the possibility to write/read unformatted files
are get() and put(). To read a byte, you can use get(), and to write a
byte, use put().
Some useful functions in c++ are: tellg(), tellp(), seekp(), ignore()
getline(), peek(), remove(), putback() and flush().
11. 8 Answers
Self-Assessment Questions
1. using constructor function of the class, using member function open() of
the class.
2. ios::app
3. True
4. open()
5. True
6. rdstate()
7. get() and put()
8. read()
9. tellg()
10. ignore()
11. putback()
12. Flase
Terminal Questions
1. There are two ways to open a file. These are: using the constructor
function of the class, and using the member function open() of the class.
For more details refer section 11.2.1.
2. The most usual way is:
Xfstream File(“cpp-home.txt”);
if (!File)
{
cout << “Error opening the file! Aborting…\n”;
exit(1);
For more details refer section 11.2.2.
Structure:
12.1 Introduction
Objectives
12.2 Class Templates
Implementing a class template
Class template with multiple parameters
12.3 Function Templates
Implementing function templates
Using template functions
Function templates with multiple parameters
Overloading Function Templates
12.4 Template Instantiation
12.5 Class Template Specialization
Template class partial specialization
12.6 Template Function Specialization
12.7 Template Parameters
12.8 Static Members and Variables
12.9 Templates and Friends
12.10 Templates and Multiple – File Projects
12.11 Summary
12.12 Terminal Questions
12.13 Answers
12.1 Introduction
In the previous unit you have studied the methods to open and close files
along with the methods to check whether a file opening was successful or
not. You have also studied the I/O status flags, binary files and some very
useful functions in C++. In this unit you are going to study in detail about the
templates in C++. Template in C++ is newly added concept that enables us
to define generic classes and functions and hence provides support for
generic programming. Generic programming is an approach where generic
types are used as parameters in algorithms so that they work for variety of
suitable data types and data structures. We can use templates to create
family of class and functions. For example, a class template for an array will
}
int operator*(vector &y) //scalar product
{
int sum=0;
for( int i=0; i<size; i++)
sum= sum + this-> v[i] * y . v[i];
return sum;
}
};
The vector class can store an array of int numbers and perform the scalar
product of two int vectors as shown below:
int main()
{
int x[3] = {1, 2, 3};
int y[3] = {4, 5, 6};
vector v1(3); //creates a null vector of three integers
vector v2(3);
v1 = x; //creates v1 from the array x
v2= y;
int R = v1 * v2;
cout << “R = “ << R;
return 0;
}
Now let’s assume that we want to define a vector that can store an array of
float values. This can be done by replacing the appropriate int declarations
with float in the vector class. This means that the complete class needs to
be redefined.
This helps us define a vector class with the data type as a parameter and
then use this class to create a vector of any data type instead of defining a
new class every time. This can be achieved by using the templates.
12.2.1 Implementing a Class Template
As it has already been mentioned, the templates allow us to define generic
classes. It is a simple process to create a generic class using a template
with anonymous type. The general format of class template is as follows:
class classname
{
//class member specification with anonymous type T wherever
appropriate.
………….
};
For example, the definition of vector class is given below:
template<class T>
class vector
{
T* v; //type T vector
int size;
public:
vector(int m)
{
v= new T [ size = m];
for (int i=0; i<size; i++)
v[i]=0;
}
vector (T *a)
{
for(int i=0; i<size; i++)
v[i] = a[i];
}
T operator* (vector &y)
{
T sum = 0;
for (int i =0; i<size ; i++)
sum = sum + this -> v[i] * y. v[i];
return sum;
}
The class template definition is similar to an ordinary class definition except
the prefix template<class T> and the use of type T. This prefix tells the
compiler that a template is to be declared and T is used as a type name in
declarations. Thus vector has become a parameterized class with type T as
its parameter. T can be substituted with any data type including the user-
Manipal University Jaipur B2114 Page No.: 268
Object Oriented Programming – C++ Unit 12
T sum =0;
for (int i=0; i<size; i++)
sum = sum + this -> v[i] * y.v[i];
return sum;
}
};
int main()
{
int x[3] = {1, 2, 3};
int y[3] = {4, 5, 6};
vector <int> v1;
vector <int> v2;
v1 = x;
v2 = y;
int R = v1 * v2;
cout << “R =” << R << “\n”;
return 0;
}
The output of the above program will be:
R = 32
The following program shows the use of a vector class template for
performing the scalar product of float type vectors.
#include<iostream>
using namespace std;
const size = 3;
template <class T>
class vector
{
T* v; //type T vector
public:
vector()
{
v = new T[size];
for (int i=0; i<size; i++)
v[i] = 0;
}
vector (T* a)
{
for (int i=0; i<size; i++)
v [i] = a[i];
}
T operator*(vector &y)
{
T sum =0;
for (int i=0; i<size; i++)
sum = sum + this -> v[i] * y.v[i];
return sum;
}
};
int main()
{
float x[3] = {1.1, 2.2, 3.3};
int y[3] = {4.4, 5.5, 6.6};
vector <float> v1;
vector <float> v2;
v1 = x;
v2 = y;
int R = v1 * v2;
cout << “R =” << R << “\n”;
return 0;
}
The output of the above program will be:
R = 38.720001
{
………
……….
body of the class
…………
};
The program below shows the use of template class with two generic data
types.
#include<iostream>
using namespace std;
template< class T1, class T2>
class demo
{
T1 a;
T2 b;
}
public:
Test(T1 x, T2 y)
{
a=x;
b=y;
}
void show()
{
cout << a << “ and “ << b << “\n”;
}
};
int main()
{
demo <float, int> d1 (1.11, 567);
demo <int, char> d2 (200, ‘A’);
d1.show();
d2.show();
return 0;
}
The function template is similar to class template. We must use the template
parameter T as and when necessary in the function body and in its
argument list.
Function templates are implemented like regular functions, except they are
prefixed with the keyword template. Here is a sample with a function
template.
#include <iostream>
using namespace std;
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b;
}
cout << "max(10, 15) = " << max(10, 15) << endl;
cout << "max('k', 's') = " << max('k', 's') << endl;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl;
}
Output:
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
12.3.3 Function templates with multiple parameters
Multiple parameters are supported by function templates. We can write a
function that compares three parameters and returns the largest of the
three. For example, in the program code shown below the function template
named findLargest(), returns the largest amongst the three parameters.
template <class T>
T findLargest(T x, T y, T z)
{
T max;
if( x > y)
max= x;
else
max = y;
if ( z> max)
max = z;
return max;
}
The three parameters are passed in the findLargest() function in the above
code. A temporary variable max is declared within this function. The data
type of max variable is the same as that of the function parameters. i.e., if
the three integers are passed to the function, then max is also an integer; if
three doubles are passed, then max is also of type double. If the first
parameter x passed to the findLargest() is larger than the second parameter
y, then x s assigned to max otherwise y is assigned to max. Then if the third
parameter z is larger than max, then z is assigned to max. And finally value
of max is returned. The variables x, y, z and max may be of any type for
which the greater than (>)operator and the assignment (+) operator have
been defined, but x, y, z and max must be of the same type because they
are all defined to be the same type named T.
12.3.4 Overloading Function Templates
Like ordinary functions it is possible to overload function templates. In this
section, we are going to discuss overloading when the templates are
involved. That is, you can have many function definitions with the same
function name so that when that name is used in function call, the C++
compiler decides which of the functions to be called.
Let us see the following program to understand the overloading of function
templates,
//maximum of two int values
int const& max (int const& a, int const& b)
{
return a < b ? b : a;
}
//maximum of two values of any type
template <typename>
T const& max (T const& a, T const& b)
{
return a < b ? b:a;
}
//maximum of three values of any type
template<typename T>
int main()
{
max(4, 5, 6); //calls the template for three arguments
max(8.1, 9,.1); //calls max<double> (by argument detection)
max (‘c’, ‘d’); // calls max<char> (by argument detection)
max(7,42) //calls the nontemplate for two ints
max< > (7, 42); //class max<int> (by argument deduction
Manipal University Jaipur B2114 Page No.: 276
Object Oriented Programming – C++ Unit 12
void g(){};
};
int main() {
Z<int>* p_zi; //instantiation of class Z<int> not required
Z<float>* p_zf; //instantiation of class Z<float> not required
return 0;
}
This time the compiler does not generate any definitions! There is no
need for any definitions. It is similar to declaring a pointer to an
undefined class or structure.
5. Consider the following sample. This is an example of implicit
instantiation of a function template.
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b;
}
void main() {
int I;
I = max(10, 15); //implicit instantiation of max(int, int)
char c;
c = max('k', 's'); //implicit instantiation of max(char, char)
}
In this case the compiler generates functions max(int, int) and max(char,
char). The compiler generates definitions using the template function
max.
6. Consider the following sample. This is an example of explicit
instantiation of a function template.
template <class T>
void Test(T r_t) {
}
int main() {
//explicit instantiation of Test(int)
template void Test<int>(int);
return 0;
}
In this case the compiler would generate function Test(int). The compiler
generates the definition using the template function Test.
7. If an instantiation of a class template is required, and the template
declared but not defined, the program is ill-formed.
template <class T> class X ;
int main() {
X<int> xi;
return 0;
}
8. Instantiating virtual member functions of a class template that does not
require instantiation is implementation defined. For example, in the
following sample, virtual function X<T>::Test() is not required, VC5.0
generates a definition for X<T>::Test.
template <class T>
class X {
public:
virtual void Test() {}
};
int main() {
X<int> xi; //implicit instantiation of X<int>
return 0;
}
In this case the compiler generates a definition for X<int>::Test, even if it
is not required.
Self Assessment Questions
5. A class generated from a class template is called ________________.
6. Instantiating virtual member functions of a class template that does not
require instantiation is implementation defined. (True/False)
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
cout << "max(\"Aladdin\", \"Jasmine\") = " << max("Aladdin",
"Jasmine") << endl ;
return 0 ;
}
Output:
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
max("Aladdin", "Jasmine") = Aladdin
Not quite the expected results! Why did that happen? The function call
max("Aladdin", "Jasmine") causes the compiler to generate code for
max(char*, char*), which compares the addresses of the strings! One can
use template specializations to correct special cases like these or to provide
more efficient implementations for certain types. The above example can
be rewritten with specialization as follows:
#include <iostream>
#include <cstring>
using namespace std;
//max returns the maximum of the two elements
template <class T>
T max(T a, T b) {
return a > b ? a : b ;
}
// Specialization of max for char*
template <>
char* max(char* a, char* b) {
return strcmp(a, b) > 0 ? a : b ;
}
int main() {
cout << "max(10, 15) = " << max(10, 15) << endl ;
cout << "max('k', 's') = " << max('k', 's') << endl ;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
void f()
{
size++ ; //error change of template argument value
}
};
int main() {
Stack<double,10> si ;
return 0 ;
}
6. A template-parameter that could be interpreted as either a parameter-
declaration or a type-parameter, is taken as a type-parameter. For
example,
class T {};
int i;
template <class T, T i>
void f(T t) {
T t1 = i; //template arguments T and i
::T t2 = ::i; //globals T and i
}
int main() {
f('s');
return 0 ;
}
Self Assessment Questions
8. C++ allows you to specify a default template parameter. (True/False)
9. __________________________ cannot be specified in a declaration
or a definition of a specialization.
public:
static T s;
};
int main() {
X<int> xi ;
X<char*> xc ;
}
Here X<int> has a static data member s of type int and X<char*> has a
static data member s of type char*.
3. Static members are defined as follows:
#include <iostream>
using namespace std;
template <class T>
class X {
public:
static T s;
};
template <class T> T X<T>::s = 0 ;
template <> int X<int>::s = 3 ;
template <> char* X<char*>::s = "Hello" ;
int main() {
X<int> xi ;
cout << "xi.s = " << xi.s << endl ;
X<char*> xc ;
cout << "xc.s = " << xc.s << endl ;
return 0 ;
}
Program Output:
xi.s = 10
xc.s = Hello
4. Each instantiation of a function template has its own copy of the static
variable. For example,
#include <iostream>
using namespace std;
template <class T>
void f(T t) {
static T s = 0;
s = t;
cout << "s = " << s << endl;
}
int main() {
f(10);
f("Hello");
return 0;
}
Program Output:
s = 10
s = Hello
Here f<int>(int) has a static variable s of type int, and f<char*>(char*)
has a static variable s of type char*.
The table 12.1 lists the results of declaring different kinds of friends of a
class.
Table 12.1: Different kinds of friends of a class
12.11 Summary
Templates are a fairly new addition to the C++ language, and were only
recently standardized on. They are also one of the more useful features
of C++. They allow you to create classes that are more dynamic in
terms of the types of data they can handle.
A class template is a class that is implemented with one or more type
parameters left open. The class template definition is similar to an
ordinary class definition except the prefix template<class T> and the
use of type T.
This is a process of creating a specific class from a class template and
it is called as instantiation.
It is possible to use more than one generic data type in a class template
In C++ we can create functions that use variable types. These function
templates serve as an outline or pattern for a group of functions that
differ in the types of parameters they use.
Function templates are implemented like regular functions, except they
are prefixed with the keyword template.
Multiple parameters are supported by function templates.
Like ordinary functions it is possible to overload function templates.
When the compiler generates a class, function or static data members
from a template, it is referred to as template instantiation.
In some cases it is possible to override the template-generated code by
providing special definitions for specific types. This is called template
specialization.
Each template class or function generated from a template has its own
copies of any static variables or members.
With class templates, friendship can be established between a class
template and a global function, a member function of another class or
even an entire class.
Compiling templates when required forces a restriction for multi-file
projects: the implementation (definition) of a template class or function
must be in the same file as its declaration
12.13 Answers
Self Assessment Question
1. Templates
2. template<class T>
3. Function templates
4. True
5. Generated class
6. False
7. Template specialization
8. True
9. Default arguments
10. True
11. True
12. Class templates
Terminal Questions
1. It is a simple process to create a generic class using a template with
anonymous type. The general format of class template is as follows:
class classname
{
//class member specification with anonymous type T wherever
appropriate.
………….
};
For more details refer section 12.2.1
References:
Object Oriented Programming with C++ - Sixth Edition, by
E Balagurusamy. Tata McGraw-Hill Education.
Object Oriented Programming In C++, 4/E by Robert Lafore. Pearson
Education India.
C++ Templates: The Complete Guide, By David Vandevoorde, Nicolai
M. Josuttis. Addison Wesley Professional.
C++ for Programmers, By Paul Deitel, Harvey M. Deitel. Pearson
Education.
13.1 Introduction
In the previous unit you studied about the templates in C++. You got a clear
idea of ‘class’ and ‘function’ templates. You also studied about the template
instantiation, template specialization along with the template parameters.
You also got some idea of using static members and variables in templates
as well as using friend functions in templates. In this unit you will study in
detail the standard template library.
Many people felt that C++ classes were inadequate in situations requiring
containers for user-defined types, and methods for common operations on
them. For example, you might need self-expanding arrays, which can easily
be searched, sorted, added to or removed from without messing with
memory reallocation and management. Other Object-oriented languages
used templates to implement this sort of thing, and hence they were
incorporated into C++.
13.2.1 Containers
The containers are objects that hold data of the same type. It is a way data
is organized in memory. The STL containers are implemented by template
classes, and hence, can be customized to hold many data types.
Very many container types are provided by STL which represents objects
that contain other objects. The major ones are sequence containers,
associative containers and derived containers. The classification of
containers is shown in figure 13.2.
Containers
As you can see in figure 13.2, the standard sequence containers include
vector, deque and list. Data is stored in linear sequence in sequence
containers. The standard associative containers can be categorized into set,
multiset, map and multimap. Associative containers are a generalization of
sequences. Sequences are indexed by integers; associative containers can
be indexed by any type. The derived containers can be classified into three
types i.e., stack, queue and priority queue.
13.2.2 Iterators
An iterator is an object (like a pointer) that points to an element in a
container. Iterators can be used to move through the contents of the
container. Iterators are handled just like pointers. Iterators can be
incremented or decremented. They connect algorithms with containers, and
play an important role in the manipulation of data stored in the container.
Iterators are like location specifiers for containers or streams of data, in the
same way that an int* can be used as a location specifier for an array of
integers, or an ifstream can be used as a location specifier for a file.
The STL implements five different types of iterators. These are: input
iterators (which can only be used to read a sequence of values), output
iterators (which can only be used to write a sequence of values), forward
iterators (which can be read, written to, and moved forward), bidirectional
iterators (which are like forward iterators but can also move backwards) and
random access iterators (which can move freely any number of steps in one
operation). The table 13.1 shown below illustrates the iterators and their
characteristics:
Table 13.1: Iterators and their characteristics
Access Direction of
Iterator I/O capability Remark
Method movement
Input Linear Forward Only Read Only Cannot be saved
Output Linear Forward Only Write only Cannot be saved
Forward Linear Forward Only Read/Write Cannot be saved
Bidirectional Linear Forward and Read/Write Cannot be saved
backward
Random Random Forward and Read/Write Cannot be saved
backward
Each element is related to other elements by its position along the line.
They all expand themselves to allow insertion of elements, and all of them
support a number of operations on them.
There are three types of sequence containers in the STL. These, as their
name suggests, store data in linear sequence. They are the vector, deque
and list:
vector<Type>
deque<Type>
list<Type>
To choose a container, decide what sort of operations you will most
frequently perform on your data, and then, use the following table to help
you.
Table 13.2: Time overhead of operations on sequence containers
{
v.push_back(ival);
cout.width(6);
cout << nitems << ": " << v[nitems++] << endl;
}
if (nitems)
{
sort(v.begin(), v.end());
for (vector<int>::const_iterator viter=v.begin(); viter!=v.end(); ++viter)
cout << *viter << " ";
cout << endl;
}
return(EXIT_SUCCESS);
}
Note how the element sort takes v.begin() and v.end() as range arguments.
This is very common in the STL, and you will meet it again. The STL
provides specialized variants of vectors: the bitset and valarray. The former
allows a degree of array-like addressing for individual bits, and the latter is
intended for numeric use with real or integer quantities. To use them,
include the <bitset> or <valarray> header files (these are not always
supported in current STL implementations). Be careful when you erase() or
insert() elements in the middle of a vector. This can invalidate all existing
iterators. To erase all elements in a vector, use the clear() member function.
13.3.2 Deque
#include <deque>
The double-ended queue, deque (pronounced "deck") has properties similar
to those of a vector. But as you can observe from the name, it is possible to
perform insertions and deletions at both the ends of a deque.
{
public:
Card() { Card(1,1); }
Card( int s, int c ) { suit = s; card = c; }
friend ostream & operator<<( ostream &os, const Card &card );
int value() { return( card ); }
private:
int suit, card;
};
ostream & operator<<( ostream &os, const Card &card ) {
static const char *suitname[] = { "Hearts", "Clubs", "Diamonds", "Spades"
};
static const char *cardname[] = { "Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King" };
return( os << cardname[card.card-1] << " of " << suitname[card.suit] );
}
class Deck {
public:
Deck() { newpack(); };
void newpack() {
for ( int i = 0; i < 4; ++i ) {
for ( int j = 1; j <= 13; ++j ) cards.push_back( Card( i, j ) );
}
}
// shuffle() uses the STL sequence modifying algorithm,
random_shuffle()
void shuffle() { random_shuffle( cards.begin(), cards.end() ); }
bool empty() const { return( cards.empty() ); }
Card twist() { Card next = cards.front(); cards.pop_front(); return(next);
}
private:
return( EXIT_SUCCESS );
}
The card game is a version of pontoon, the idea being to get as close to 21
as possible. Aces are counted as one, and picture cards, as 10. Try to
Manipal University Jaipur B2114 Page No.: 308
Object Oriented Programming – C++ Unit 13
been used with erase() - they will be invalid. Other iterators, however, will
still be valid after erase() or insert().
Self Assessment Questions
5. The three types of sequence containers in the STL are________,
_______ and _______,
6. Vector allows _______ of the elements.
7. _________ are the best suited for applications in which it is required to
add or delete elements to and from the middle.
8. ___________list access function returns iterator pointing to the first
element.
13.6 Iterators
#include <iterator> // do not normally need you to include this
yourself
An iterator you are already familiar with is a pointer into an array:
char name[] = "Word";
char ch, *p;
p = name; // or &name[0] if you like
ch = p[3]; // Use [] for random access
ch = *(p+3);// Equivalent to the above
*p = 'C'; // Write "through" p into name
while ( *p && *p++ != 'r' ); // Read name through p
We can observe from the above program that the iterators are very flexible
and powerful. As you can see, the above code uses variable ‘p’ in five
different ways. We take it for granted that the compiler generates the
appropriate offset for array elements, using the size of a single element.
The STL iterators you have already met are those returned by the begin()
and end() container access functions, that let you loop over container
elements. For example:
List<int> l;
List<int>::iterator liter; // Iterator for looping over list elements
for ( liter = l.begin(); liter != l.end(); ++liter ) {
*liter = 0;
}
Manipal University Jaipur B2114 Page No.: 312
Object Oriented Programming – C++ Unit 13
The end-of-loop condition is slightly different from normal. Usually the end
condition would be a less than < comparison, but as you can see from the
table of iterator categories below, not all iterators support <, so we
increment the iterator from begin() and stop just before it becomes equal to
end(). It is important to note that, for virtually all STL purposes, end() returns
an iterator "pointing" to an element just after the last element, which it is not
safe to dereference, but is safe to use in equality tests with another iterator
of the same type. Sometimes, better performance is given by the pre
increment operator (++). The reason for this is that there is no requirement
of creating a temporary copy of the previous value, though the compiler
usually optimizes this way.
Iterators can be termed as the generalized abstraction to the pointers which
are designed to allow programmers to access different container types in a
consistent way. To put it more simply, you can think of iterators as a "black
box" between containers and algorithms. When you use a telephone to
directly dial someone in another country, you do not need to know how the
other phone system works. You can talk to the remote person provided it
supports certain basic operations like dialing, ringing, reporting an engaged
tone, hanging up after the call. . Similarly, if the minimum required iterator
types for an algorithm are supported by a container class, then the algorithm
will work with the container. This is important because it means that you can
use algorithms such as the sort and random_shuffle as we've seen in the
earlier examples. The authors of the algorithm are not required to know
which containers they are acting on, provided we support the type of iterator
required by that algorithm. The sort algorithm, for example, only needs to
know how to move through the container elements, how to compare them,
and how to swap them.
There are 5 categories of iterator:
Random access iterators
Bidirectional iterators
Forward iterators
Input iterators
Output iterators
They are not all as powerful in terms of the operations they support - most
do not allow random access- as we've seen in the difference between
vector and list. The figure 13.4 is the summary of the iterator hierarchy, the
most capable at the top, and the operations supported on the right.
Iterator Type Operations Supported
^ +-------------------------------------+
/ \ \ == != < > >= <= /
/ \ \ ++ -- + - += -= /
/ [] \ \ *p= /
/Random \ \ -> [] /
/ Access \ \ =*p /
/-----------\ \-------------------------/
/Bidirectional\ \ == != ++ -- /
/ \ \ *p= -> =*p /
/-----------------\ \-------------------/
/ Forward \ \ == != ++ /
/ \ \ *p= -> =*p /
/-----------+-----------\ \-------+-----/
/Input | Output\ \ == !=| ++ /
/ | \ \++ ->|*p=/
+--------------+--------------+ \ =*p| /
\ | /
\ |/
\ /
V
The higher contains all the functionality of the layers below it. In addition, it
contains some more functionalities. Only random iterators provide the ability
to add or subtract an integer to or from the iterator, like *(p+3). If you write
an iterator, it must provide all the operations needed for its category, e.g. if it
is a forward iterator, it must provide ==, !=, ++, *p=, -> and =*p. It is to be
taken care that ++p and p++ are different. ++p increments the iterator and
Manipal University Jaipur B2114 Page No.: 314
Object Oriented Programming – C++ Unit 13
then it returns a reference to itself. p++ first returns a copy of itself, and then
increments.
Operators must retain their conventional meaning, and elements must have
the conventional copy semantics. In a nutshell, this means that the copy
operation must produce an object that, when tested for equality with the
original item, must match. Because only random iterators support integer
add and subtract, all iterators except output iterators provide a distance()
function to find the "distance" between any two iterators. The type of the
value returned is:
template<class C> typename iterator_traits<C>::difference_type
This is useful if, for example, you find() a value in a container, and want to
know the "position" of the element you have found.
map< key_type, data_type >::iterator im;
map< key_type, data_type >::difference_type dDiff;
im = my_map.find( key );
dDiff = distance( my_map.begin(), im );
This operation will be inefficient if the random access iterators are not
supported by the containers because in that case, it will have to "walk
through" the elements comparing the iterators.
Just as you can declare pointers to const objects, you can have iterators to
const elements. The const_ prefix is used for this purpose.
e.g. vector::iterator i; // Similar to my_type *i
vector::const_iterator i; // Similar to const my_type *i
The iterator_traits for a particular class is a collection of information, like the
"iterator tag" category, which helps the STL "decide" on the best algorithm
to use when calculating distances. The calculation is trivial for random
iterators, but if you have only forward iterators, then it may be a case of
slogging through a linked list to find the distance. If you write a new class of
container, then this is one of the things you must be aware of. As it
happens, the vector, list, deque, map and set - all provide at least
Bidirectional iterators, but if you write a new algorithm, you should not
assume any capability better than that which you really need. The lower the
category of iterator you use in your algorithm, the wider the range of
containers your algorithm will work with.
Although the input and output iterators seem rather poor in capability, in fact
they do add the useful ability to read and write containers to or from files.
This is demonstrated in the program below:
#include <stdlib.h>
// C++ STL Headers
#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>
using namespace std;
int main( int argc, char *argv[] ) {
int i, iarray[] = { 1,3,5,7,11,13,17,19 };
fstream my_file("vector.dat",ios::out);// Add |ios::nocreate to avoid
// creation if it doesn't exist
vector<int> v1, v2;
for (i = 0;i<sizeof(iarray)/sizeof(iarray[0]); ++i) v1.push_back(iarray[i]);
// Write v1 to file
copy(v1.begin(),v1.end(), ostream_iterator<int,char>(my_file," "));
cout << "Wrote vector v1 to file vector.dat" << endl;
// Close file
my_file.close();
// Open file for reading or writing
my_file.open( "vector.dat", ios::in|ios::out );
// Read v2 from file
copy( istream_iterator<int,char>(my_file), // Start of my_file
istream_iterator<int,char>(), // Val. returned at eof
inserter(v2,v2.begin()));
cout << "Read vector v2 from file vector.dat" << endl;
for ( vector<int>::const_iterator iv=v2.begin(); iv != v2.end(); ++iv )
cout << *iv << " ";
13.7 Summary
STL, is a C++ library of container classes, algorithms, and iterators; it
provides many of the basic algorithms and data structures of computer
science.
There are many components present in STL. But there are three major
components in STL. They are: containers, algorithms and iterators.
The containers are objects that hold data of the same type. It is the way
data is organized in memory.
An iterator is an object (like a pointer) that points to an element in a
container. Iterators can be used to move through the contents of the
container.
Algorithms are functions that can be used across a variety of containers
for processing their contents.
The function object is a function that has been wrapped in a class so
that it looks like an object.
Sequence containers store elements in a linear sequence. There are
three types of sequence containers in the STL- the vector, the deque
and the list.
The vector class is similar to an array. Vector allows random access of
the elements, with a constant time overhead, O(1). It is possible to
Manipal University Jaipur B2114 Page No.: 317
Object Oriented Programming – C++ Unit 13
perform insertions and deletions at both the ends of Lists. Lists are best
suitable for the applications where it is required to add or delete the
elements to and from the middle.
Associative containers are designed to support direct access to
elements using keys. They are not sequential. There are four types of
associative containers: set, multiset, map and multimap.
The derived containers provided by STL are: stack, queue and priority
queue. These are also known as container adapters.
13.9 Answers
Self Assessment Questions
1. Containers, algorithms, iterators
2. Containers
3. Iterator
4. STL algorithms
5. Vector, deque and list
6. Random access
7. Lists
8. begin()
9. Set, multiset, amp and multimap
10. Stack, queue and priority queue
11. Five
12. True
Terminal Questions
1. STL provides a number of container types, representing objects that
contain other objects. The STL contains sequence containers and
associative containers. For more details refer section 13.2.
2. There are three types of sequence containers in the STL They are: the
vector, the deque and the list. For more details refer section 13.3.
References:
Object-Oriented Programming with C++ - Sixth Edition, by
E Balagurusamy. Tata McGraw-Hill Education.
The C++ Programming Language, fourth edition, by Bjarne Stroustrup.
Addison-Wesley.
Object-Oriented Programming with ANSI and Turbo C++, by Kamthane
http://clinuxpro.com/
14.1 Introduction
In the previous unit you have studied standard template library and its
components. In this unit you will study the concept of exception handling in
C++. The program which we write might have bugs. The common types of
errors which occur in our programs are – logical and syntactic errors. The
reason for logical errors is the poor understanding of the problem and
solution procedure. Syntactic errors occur due to the poor understanding of
the programming language. These errors can be detected by debugging
and testing procedures. Sometimes we come across errors other than the
cin >> b;
int x= a-b;
try
{
if(x!=0)
{
cout << “result (a/x) =” << a/x << “\n”;
}
else //there is an exception
{
throw (x); //throws int object
}
}
catch(int i) //catches the exception
{
cout << “exception caught : divide by zero error\n”;
}
cout << “end”;
return 0;
}
The output of the above program will be:
First run
Enter the values of a and b: 10 5
result (a/x) = 2
end
Second run
Enter the values of a and b: 5 5
exception caught: divide by zero
end
You can see that the first run has shown a successful execution. In the first
run, there is no exception and hence, catch block is skipped and the
execution resumes with the first line after the catch. You can observe that in
second run the ‘divide by zero’ error occurs as the denominator x becomes
zero. Using the object x the exception is thrown. As the data type of the
exception object is int the catch statement containing int type argument
catches the exception and the necessary message is displayed.
Most often, exceptions are thrown by functions that are invoked from within
the try blocks. The point at which throw is executed is called throw point.
The control cannot be returned to the throw point once the exception is
thrown to the catch block. This relationship is shown in figure 14.2.
The code below shown is the general format of this kind of code
type function (arg list) // function with exception
{
……….
………..
throw (object); //throws exception
………
………
}
……….
……….
try
{
………
……… invoke function here
……..
}
catch(type arg) // catches exception
{
……….
………. Handles exception here
……….
}
……….
The program below illustrates how a try block invokes a function that
generates an exception.
// throw point outside the try block
#include<iostream.h>
void divide (int x, int y, int z)
{
cout << “\n we are inside the function \n”;
if ((x-y)! =0)
{
int R = z/ (x-y)
cout << “Result =” << R << “\n”;
}
else
{
throw(x-y) //throw point
}
}
void main()
{
try
{
cout << “ we are inside the try block \n”;
divide (10,20,30) //invoke divide()
divide (10,10,10) // invoke divide()
}
catch(int i)
{
{
//statements to manage exceptions
}
Here the type shows the type of the exceptions to be handled by the catch
block. The parameter arg is an optional parameter name. Between the two
braces the exception handling code is placed. The catch statement catches
an exception whose type matches with the type of catch argument. When it
is caught, the code in the catch block is executed.
The parameter can be used in the exception handling code if the parameter
in the catch statement is named. After the handler is executed, the control is
transferred to the statements immediately following the catch blocks.
If an exception is not caught due to mismatch, then the program will
terminate abnormally. If an exception is not caught by catch statements then
the catch block is simply skipped.
14.5.1 Multiple catch statements
Sometimes program segment has more than one condition to throw an
exception. In such cases you can associate more than one catch blocks
with a try block. The syntax to achieve this task is shown below:
try
{
//try block
}
catch (type1 arg)
{
//catch block1
}
catch (type2 arg)
{
//catch block2
}
……..
……..
catch(typeN arg)
{
//catch blockN
}
void main()
{
cout << “testing multiple catches\n”;
cout << “x ==1 \n”;
test (1);
cout << “x==0 \n”;
test(0);
cout << “x==-1 \n”;
test (-1);
cout << “x==2 \n”;
test (2);
}
The output of the above program will be:
testing multiple catches
x==1
caught an integer
end of try cacth system
x==0
caught a character
end of try catch system
x==-2
end of try block
end of try catch system
As you can observe from the above program, when it is executed first the
function test() with x=1 is invoked and hence throws x an int exception.
There is match of type of parameter m in catch2 and hence the catch2
handler is executed. The function test() with x=0 is invoked immediately
after the execution of catch2 handler. This type the function throws ‘x’, a
character type exception and hence the first handler is executed. Finally, the
handler catch3 is executed when a double exception is thrown. You should
note that each time only the handler which catches the exception is
executed and all the rest handlers are skipped.
When no exception is thrown by the try block and if there is a normal
execution, then the control is transferred to the first statement after the last
catch handler associated with that try block.
NegativeNumber()
{
cout << “exception: Negative input” << endl;
}
};
Again, the class constructor prints an appropriate message on the user
console. Once you create the two user-defined cl for classes for exception,
you need to use these data types in the catch block of your error handler
code. To catch OutofRange, we the catch block will be as shown below:
catch(OutofRange)
{
//error handler code
}
Similarly to catch negative number exception, the catch block will be as
follows:
catch(NegativeNumber)
{
//error handler code
}
Next you need to throw exceptions of these types in your try block. For this
you need to construct an object of the user-defined exception and then use
it as a parameter in the throw statement. For example: to throw OutofRange
exception, the following code will be used:
OutofRange e;
throw e;
divide(10.5, 2.0);
divide(20.0, 0.0);
}
catch(double)
{
cout << “caught double inside main \n”;
}
cout << “end of main \n”;
}
The output of the above program will be:
inside main
inside function
division = 5.25
end of function
inside function
caught double inside function
caught double inside main
end of main
When an exception is rethrown, it will not be caught by the same catch
statement or any other catch in the group. Instead, it will be caught by an
appropriate catch in outer try/catch sequence only.
A catch handler itself may detect and throw an exception. Here again, the
exception thrown will not be caught by any catch statements in that group. It
will be passed on to the next outer try/catch sequence for processing.
existing exception reaches its handler – the most common reason for this is
that the constructor for the exception object itself causes a new exception.
14.10.1 terminate()
This function is called automatically if an exception is uncaught. Like
unexpected(), terminate is actually a pointer to a function. Its default value is
the Standard C library function abort(), which immediately exits the program
with no calls to the normal termination functions (which means that
destructors for global and static objects might not be called).
No destructors are called for an uncaught exception. If you don’t wrap your
code (including, if necessary, all the code in main()) in a try block followed
by handlers and ending with a default handler (catch(...)) to catch all
exceptions, then you will take your lumps. An uncaught exception should be
thought of as a programming error.
14.10.2 set_terminate()
Using this function, it is possible to install your own terminate () function,
which returns a pointer to the terminate() function you are replacing, so you
can restore it later if you want. Your custom terminate() must take no
arguments and have a void return value. In addition, any terminate() handler
you install must not return or throw an exception, but instead must call some
sort of program-termination function. If terminate() is called, it means the
problem is unrecoverable. Like unexpected(), the terminate() function
pointer should never be null.
Self Assessment Questions
11. Rethrowing is achieved by using throw with ________.
12. Using __________ function it is possible to install your own terminate()
function.
The iostream exception class ios::failure is also derived from exception, but
it has no further subclasses.
The classes in both of the following tables 14.2 and 14.3 can be used as
they are, or they can act as base classes to derive your own more specific
types of exceptions.
Table 14.2: Exceptions derived from logic_error
domain_error Reports violations of a precondition.
Indicates an invalid argument to the function it’s thrown
invalid_argument
from.
Indicates an attempt to produce an object whose length is
length_error greater than or equal to NPOS (the largest representable
value of type size_t).
out_of_range Reports an out-of-range argument.
Thrown for executing an invalid dynamic_cast expression
Bad_cast
in run-time type identification
Bad_typeid Reports a null pointer p in an expression typeid(*p).
Base
Derived
The output of the program is as shown above because, when the object
is caught by value, it is turned into a Base object (by the copy
constructor) and must behave that way in all situations, whereas when
it’s caught by reference, only the address is passed and the object isn’t
truncated, so it behaves like what it really is, a Derived in this case.
Although you can also throw and catch pointers, by doing so you
introduce more coupling – the thrower and the catcher must agree on
how the exception object is allocated and cleaned up. This is a problem
because the exception itself may have occurred from heap exhaustion.
If you throw exception objects, the exception-handling system takes
care of all storage.
Don’t cause exceptions in destructors – Because destructors are called
in the process of throwing other exceptions, you’ll never want to throw
an exception in a destructor or cause another exception to be thrown by
some action you perform in the destructor. If this happens, it means that
a new exception may be thrown before the catch-clause for an existing
exception is reached, which will cause a call to terminate(). This means
that if you call any functions inside a destructor that may throw
exceptions, those calls should be within a try block in the destructor, and
the destructor must handle all exceptions itself. None must escape from
the destructor.
Self Assessment Questions
13. The asynchronous events can be handled by C++ exceptions.
(True/False)
14. We should check the standard library before throwing an exception.
(True/False)
14.13 Summary
Exceptions are run time anomalies or unusual conditions that a program
may encounter while executing.
There are two kinds of exceptions i.e. synchronous and asynchronous
exceptions
14.15 Answers
Self Assessment Questions
1. Exceptions
2. Synchronous, Asynchronous
3. try
4. catch block
5. throw
6. catch( type arg)
{
//statements to manage exceptions
}
7. User defined exception classes
8. termination
9. throw
10. unexpected()
11. no argument
12. set_terminate()
13. False
14. True
Terminal Questions
1. Exceptions are run time anomalies or unusual conditions that a program
may encounter while executing. The exception handling mechanism in
C++ is built upon the three keywords named as try, throw and catch. For
more details refer section 14.3.
2. Sometimes program segment has more than one condition to throw an
exception. In such cases you can associate more than one catch blocks
with a try block. For more details refer section 14.5.
3. It is possible to create your own exception class and use it as exception
type in your exception handling code instead of using pre-defined data
References:
Object Oriented Programming with C++ - Sixth Edition,
by E Balagurusamy. Tata McGraw-Hill Education.
The C++ Standard Library: A Tutorial and Handbook, By Nicolai M.
Josuttis, Addison-Wesley Professional.
Object-Oriented Programming with C++ 2Nd Ed. By Sarang, Sarang
Poornachandra, PHI Learning Pvt. Ltd.
––––––––––––––––