Date post: | 22-Aug-2014 |
Category: |
Documents |
Upload: | himanshu-chandna |
View: | 173 times |
Download: | 7 times |
LESSON PLAN
Unit Title: Object Oriented Programming [C++]Faculty: Vandana Babrekar (Pune)
Unit Code3B-503 Unit Level Unit Value:1
Daily Lecture Schedule
with dates
Name of the topic as given in RU SyllabusLearn
ing Outcomes
Assignment no., if any
Number of HoursL* T* P* Tot
al
1 Lecture 1 Object oriented Programming Concepts 1 12 Lecture 2 Class & Object 1 13 Lecture 3 C++ Getting Started 1 14 Lecture 4 Functions in C++ 1 15 Lecture 5 Control Structures 1 16 Lecture 6 Representation of Abstract Data Types &
scope of Attributes 1 1
7 Lecture 7 GROUP DISCUSSION 1 18 Lecture 8 Constructor
9 Lecture 9 Constructor [Contd.] 1 110 Lecture 10 Overloading 1 111 Lecture 11 Overloading [Contd.] 1 112 Lecture 12 Arrays13 Lecture 13 Pointers in C++ 1 114 Lecture 14 Inheritance 1 115 Lecture 15 Inheritance [Contd.] 1 116 Lecture 16 Inheritance [Contd.] 1 1 217 Lecture 17 TUTORIAL 1 118 Lecture 18 Virtual Functions 1 119 Lecture 19 Polymorphism 1 120 Lecture 20 Virtual Base Classes, Nesting Of Class 1 1 221 Lecture 21 Streams 1 122 Lecture 22 Streams [Contd.] 1 123 Lecture 23 TUTORIAL 1 1 124 Lecture 24 Working with Files25 Lecture 25 Working with Files [Contd.] 1 126 Lecture 26 Working with Files [Contd.] 1 1 227 Lecture 27 Templates 1 128 Lecture 28 Templates [Contd.] 1 129 Lecture 29 Templates [Contd.] 1 1 230 Lecture 30 Exception Handling 1 131 Lecture 31 Exception Handling [Contd.] 1 132 Lecture 32 GROUP DISCUSSION33 Lecture 33 Implementation 1 134 Lecture 34 Implementation 1 235 Lecture 35 Data Driven 1 1
36 Lecture 36 Omt 1 137 Lecture 37 CRC 1 138 Lecture 38 Design Refinement 1 139 Lecture 39 Standard Template Library 1 140 Lecture 40 Standard Template Library[Contd.] 1 141 Lecture 41 UML 1 142 Lecture 42 UML [contd.] 1 143 Lecture 43 GROUP DISCUSSION 1 1
UNIT I
Lesson 1
OBJECT ORIENTED PROGRAMMING
Objectives
Introduction to object oriented programming
Features of OOPS
Benefits of OOPS
Applications of OOPS
Basic Concept
Today in this introductory lecture , I will brief you some of the new concept of object oriented
programming . we are aware of modular/structured programming, unstructured programming which
are the traditional methods of writing a program. We also saw how the ‘main program’ is linked to
‘subprogram’ or ‘subroutine’ through ‘procedure calls [example of swapping between two telephone
calls received’]. And the trend of ‘object oriented programming’ was discussed in brief. Now lets
understand ‘object oriented programming through its programming tool…. C++ ” Fundamental
change in (object oriented programming )OOP is that a program is designed around data being
operated upon rather than upon the operations themselves. C++ is an example of Object Oriented
Programming . It is expanded version of C .The limitations of C language are evident when a
software project is too large to be handled. In some circumstances, error occur at some place and
some patch up programs are added to rectify that error.These programs introduce an unexpected
error at some other location and this process continues.
In 1980 Bjarne Stroustrup addressed this problem by adding several extensions to C language. The
most important addition was the concept of CLASS . The addition made were mainly aimed at
extending the language in such a way that it supports object-oriented programming.
OBJECT ORIENTED PROGRAMMING PATTERN
Inspiring factor in the invention of object-oriented approach is to remove some of the flaws
encountered in the procedural approach. OOP treats data as a critical element in the program
development and does not allow it to flow freely around the system. It ties data more closely to the
functions that operate on it, and protects it from accidental modification from outside functions.
OOP allows decomposition of a problem into a number of entities called objects and then builds data
and functions around these objects.
Following fig shows the organization of data and functions in object-oriented programs .
The data of an object can be accessed only by the functions associated with that object. However,
functions of one object can access the functions of other objects.
Object A Object B
Communication
Object C
Organization of data and functions in OOP
CHARACTERISTICS OF C++:
Emphasis is on data rather than procedure.
Programs are divided into what are known as objects.
Data structures are designed such that they characterize the objects.
Functions that operate on the data of an object are tied together in the data structure.
DATA
FUNCTION
DATA
FUNCTION
DATA
FUNCTION
Data is hidden and cannot be accessed by external functions.
Objects may communicate with each other through functions.
New data and functions can be easily added whenever necessary.
Follows bottom-up approach in program design.
Definition: “Object-oriented programming as an approach that provides a way of modularizing
programs by creating partitioned memory area for both data and functions that can be used as
templates for creating copies of such modules on demand.”
Thus, an object is considered to be partitioned area of computer memory that stores data and set of
operations that can access that data. Since the memory partitions are independent, the objects can
be used in a variety of different programs without modifications.
BASIC CONCEPTS OF OBJECT-ORIENTED PROGRAMMING.
It is necessary to understand some of the concepts used extensively in object-oriented
Programming.
They are:
Objects
Classes
Data abstraction and encapsulation
Inheritance
Polymorphism
Dynamic binding
Message passing
OBJECTS:
Objects are the basic run-time entities in an object-oriented system. They may represent a
person, a place, a bank account, a table of data or any item that the program has to handle. They may
also represent user-defined data such as vectors, time and lists.
Objects take up space in the memory and have an associated address like a record in Pascal,
or a structure in C.
When a program is executed, the objects interact by sending messages to one another. For
example, if "customer" and "account" are two objects in a program, then the customer object may
send a message to the account object requesting for the bank balance. Each object contains data, and
code to manipulate the data. Objects can interact without having to know details of each other's data
or code. It is sufficient to know the type of message accepted, and the type of response returned by
the objects. Although different authors represent them differently.
Fig. Shows two notations that are popularly used in object-oriented analysis and design.
Object: STUDENT
DATA
Name
Date-f-birth
Marks
FUNCTIONS
Total
Average
Display
Two ways of representing an object
Classes:
Objects contain data, and code to manipulate that data. The entire set of data and code of an
object can be made a user-defined data type with the help of a class. In fact, objects are variables of
the type class. Once a class has been defined, we can create any number of objects belonging to that
class. Each object is associated with the data of type class with which they are created.
Definition : A class is a collection of objects of similar type.
STUDENTTotal
Average
Display
For e.g., mango, apple and orange are members of the class fruit. Classes are user-defined data types
and behave like the built-in types of a programming language. The syntax used to create an object is
no different than the syntax used to create an integer object in C. If fruit has been defined as a class,
then the statement
Fruit mango;
will create an object mango belonging to the class fruit.
Data Abstraction and Encapsulation:
The wrapping up of data and functions into a single unit (called class) is known as encapsulation.
Data encapsulation is the most striking feature of a class. The data is not accessible to the outside
world, and only those functions, which are wrapped in the class, can access it. These functions
provide the interface between the object's data and the program. This insulation of the data from
direct access by the program is called data hiding or information hiding.
Abstraction refers to the act of representing essential features without including the background
details or explanations.
Classes use the concept of abstraction and are defined as a list of abstract attributes such as size,
weight and cost, and functions to operate on these attributes. They encapsulate all the essential
properties of the objects that are to be created. The attributes are sometimes called data members
because they hold information. The functions that operate on these data are sometimes called
methods or member functions.
Since the classes use the concept of data abstraction, they are known as Abstract Data Types (ADT)
Inheritance:
Inheritance is the process by which objects of one class acquire the properties of objects of another
class. For example, the bird 'robin' is a part of the class “flying bird' which is again a part of the class
'bird'. The principle behind this sort of division is that each derived class shares common
characteristics with the class from which it is derived as illustrated in Fig.
Concept of inheritance provides the idea of reusability. This means that we can add additional
features to an existing class without modifying it. This is possible by deriving a new class from the
existing one. The new class will have the combined features of both the classes. The real appeal and
power of the inheritance mechanism is that it allows the programmer to reuse a class that is almost,
but not exactly, what he wants, and to tailor the class in such a way that it does not introduce any
undesirable side-effects into the rest of the classes.
Note that each sub-class defines only those features that are unique to it. Without the use of
classification, each class would have to explicitly include all of its features.
Fig. Property inheritance
Polymorphism
Polymorphism, means the ability to take more than one form.
An operation may exhibit different behaviors in different instances. The behavior depends
upon the types of data used in the operation.
Bird
AttributesFeathersLay eggs
Flying Bird Attributes----------------
Non-Flying Bird Attributes----------------
Robin Attributes-------------
SwallowAttributes-------------
Penguin Attributes-------------
Kiwi Attributes-------------
For e.g., consider the operation of addition of two numbers, the operation will generate a
sum. If the operands are strings, then the operation would produce a third string by concatenation.
The process of making an operator to exhibit different behaviors in different instances is
known as operator overloading.
Figure below illustrates that a single function name can be used to handle different number and
different types of arguments. This is something similar to a particular word having several different
meanings depending on the context. Using a single function name to perform different types of tasks
is known as function overloading.
Polymorphism plays an important role in allowing objects having different internal structures to
share the same external interface. This means that a general class of operations may be accessed in
the same manner even though specific actions associated with each operation may differ.
Polymorphism is extensively used in implementing inheritance.
Fig. Polymorphism
Dynamic Binding
Binding refers to the linking of a procedure call to the code to be executed in response to the call.
Dynamic binding (also known as late binding) means that the code associated with a given procedure
call is not known until the time of the call at run-time. It is associated with polymorphism and
inheritance. A function call associated with a polymorphism reference depends on the dynamic type
of that reference.
ShapeDraw ()
Circle objectDraw (circle)
Box objectDraw (box)
Triangle objectDraw (triangle)
E.g. Consider the procedure "draw" in Fig. By inheritance, every object will have this procedure. Its
algorithm is, however, unique to each object and so the draw procedure will be redefined in each
class that defines the object. At run-time, the code matching the object under current reference will
be caned.
Message Passing
An object-oriented program consists of a set of objects that communicate with each other. The
process of programming in an object-oriented language, therefore, involves the following basic
steps:
1. Creating classes that define objects and their behavior,
2. Creating objects from class definitions, and
3. Establishing communication among objects.
Objects communicate with one another by sending and receiving information much the same way as
people pass messages to one another. The concept of message passing makes it easier to talk about
building systems that directly model or simulate their real-world counterparts.
A message for an object is a request for execution of a procedure, and therefore will invoke a
function (procedure) in the receiving object that generates the desired result. Message passing
involves specifying the name of the object, the name of the function (message) and the information
to be sent.
Objects have a life cycle. They can be created and destroyed. Communication with an object is
feasible as long as it is a'1ive.
BENEFITS OF OOP
OOP offers several benefits to both the program designer and the user. Object-orientation
contributes to the solution of many problems associated with the development and quality of
software products. The new technology promises greater programmer productivity, better quality
of software and lesser maintenance cost. The principal advantages are:
Through inheritance, we can eliminate redundant code and extend the use of existing
classes.
We can build programs from the standard working modules that communicate with one
another, rather than having to start writing the code from scratch. This leads to saving of
development time and higher productivity.
The principle of data hiding helps the programmer to build secure programs that cannot be
invaded by code in other parts of the program.
It is possible to have multiple instances of an object to co-exist without any interference.
It is possible to map objects in the problem domain to those in the program.
It is easy to partition the work in a, project based on objects.
The data-centered design approach enables us to capture more details of a model in
implementable form.
Object-oriented systems can be easily upgraded from small to large systems.
Message passing techniques for communication between objects makes the interface
descriptions with external systems much simpler.
Software complexity can be easily managed.
While it is possible to incorporate all these features in an object-oriented system, their importance
depends on the type of the project and the preference of the programmer. There are a number of
issues that need to be tackled to reap some of the benefits stated above. For instance, object libraries
must be available for reuse. The technology is still developing and, current products may be
superseded quickly. Strict controls and protocols. need to be developed if reuse is not to be
compromised.
Developing software that is easy to use makes it hard to build. It is hoped that the object. oriented
programming tools would help manage this problem.
OBJECT ORIENTED LANGUAGES
Object-oriented programming is not the right of any particular language. Like structured.
programming, OOP concepts can be implemented using languages such as C and Pascal. However,
programming becomes clumsy and may generate confusion when the programs grow large. A
language that is specially designed to support the OOP concepts makes it easier to implement them.
The languages should support several of the OOP concepts to claim that they are object., oriented.
Depending upon the features they support, they can be classified into the following two categories:
1. Object-based programming languages, and
2. Object-oriented programming languages.
Object-based programming is the style of programming that primarily supports encapsulation and
object identity. Major features that are required for object-based programming are:
Data encapsulation
Data hiding and access mechanisms
Automatic initialization and clear-up of objects
Operator overloading
Languages that support programming with objects are said to be object-based programming
languages. They do not support inheritance and dynamic binding. Ada is a typical object-based
programming language.
Object-oriented programming incorporates all of object-based programming features along with two
additional features, namely, inheritance and dynamic binding. Object-oriented programming can
therefore be characterized by the following statement:
Object-based features + inheritance + dynamic binding
Languages that support these features include C++, Smalltalk, Object Pascal and Java. There are a
large number of object-based and object-oriented programming languages.
APPLICATIONS OF OOP
Applications of OOP are beginning to gain importance in many areas. The most popular application
of object-oriented programming, up to now, has been in the area of user interface design such as
windows. Hundreds of windowing systems have been developed, using the OOP techniques.
Real-business systems are often much more complex and contain many more objects with
complicated attributes and methods. OOP is useful in these types of applications because it can
simplify a complex problem. The promising areas for application of OOP include:
Real-time systems
Simulation and modeling
Object-oriented databases
Hypertext, hypermedia and expertext
AI and expert systems
Neural networks and Parallel programming Decision support and office automation systems
CIM/CAM/CAD systems
Object-oriented technology is certainly going to change the way the software engineers think,
analyze, design and implement future systems.
WHAT IS C++?
C++ is an object-oriented programming language. It was developed by Bjarne Stroustrup at AT&T
Bell Laboratories in Murray Hill, New Jersey, USA, in the early 1980's.
Therefore, C++ is an extension of C with a major addition of the class construct feature of Simula67.
Since the class was a major addition to the original C language,
During the early 1990's the language underwent a number of improvements and changes. In
November 1997, the ANSI/ISO standards committee standardized these changes and added several
new features to the language specifications.
C++ is a superset of C. Most of what we already know about C applies to C++ also. Therefore,
almost all C programs are also C++ programs. However, there are a few minor differences that will
prevent a C program to run under C++ compiler. We shall see these differences later and when they
are encountered.
The most important facilities that C++ adds on to C are
Classes,
Inheritance,
Function overloading, and
Operator overloading.
APPLICATIONS OF C++
C++ is a versatile language for handling very large programs. It is suitable for virtually any
programming task including development of editors, compilers, databases, communication systems
and any complex real-life application systems.
.
Since C++ allows us to create hierarchy-related objects, we can build special object oriented libraries
which can be used later by many programmers.
While C++ is able to map the real-world problem properly, the C part of C++ give the language the
ability to get close to the machine-level details.
C++ programs are easily maintainable and expandable. When a new feature need to be implemented,
it is very easy to add to the existing structure of an object. It is expected that C++ will replace C as a
general-purpose language in the near future
A SIMPLE C++ PROGRAM
Let us begin with a simple example of a C++ program that prints a string on the screen.
This simple program demonstrates several C++ features.
# include<iostream> // include header file
using namespace std;
int main()
{
cout<< “ C++ is better than C \n” // C++ statement
return();
} // end of example
Namespace
Namespace is a new concept introduced by the ANSI C++ standards committee. This define
a scope for the identifiers that are used in a program. For using the identifiers defined in the name
space scope we must include the using directive, like using namespace std. Here, std is the name
space where ANSI C++ standard class libraries are defined. All ANSI C++ programs must include
this directive. This will bring all the identifiers defined in std u the current global scope. using and
namespace are the new keywords of C++.
Return Type of main( )
In C++, main() returns an integer type value to the operating system. Therefore, every main in C++
should end with a return( 0) statement; otherwise a warning or an error might occur Since main()
returns an integer type value, return type for main() is explicitly specified as int Note that the
default return type for all functions in C++ is int.
An Example With Class :
One of the major features of C++ is classes. They provide a method of binding together data and
functions which operate on them. Like structures in C, classes are user-defined data types shows the
use of class in a C++ program.
#include<iostream>
using namespace std;
class person()
{
char name[30];
int age;
public:
void getdata(void);
void display(void);
}
void person:: getdata(void)
{
cout « "\n Enter Name: ";
cin>> name;
cout « "\n Enter Age”;
cin >> age;
}
void person :: display(void)
{
cout<<”\n Name :”<<name;
cout <<”\n age :”<<age;
}
int main()
{
person p;
p.getdata();
p.display();
return 0;
}
The output of Program is:
Enter Name: Ajay
Enter Age: 30
Name: Ajay
Age: 30
The above program defines person as a new data of type class. The class person includes two basic
data type items and two functions to operate on that data. These functions are called I member
functions. The main program uses person to declare variables of its type. Class variables are known
as objects. Here, p is an object of type person.
Class objects are used to invoke the functions defined in that class.
STRUCTURE OF C++ PROGRAM
As it can be seen from the above Program a typical C++ program would contain four sections as
shown in following Fig. These sections may be placed in separate code files and then compiled
independently or jointly.
Include files
Class Declaration
Member Function Definition
Main Function program
Structure of a C++ program
It is a common practice to organize a program into three separate files. The class declarations are
placed in a header file and the definitions of member functions go into another file. This approach
enables the programmer to separate the abstract specification of the interface (class definition) from
the implementation details (member functions definition). Finally, the main program that uses the
class is placed in a third file which "includes" the previous two files as well as any other files
required.
Summary
Object-oriented programming as an approach that provides a way of modularizing programs
by creating partitioned memory area for both data and functions that can be used as
tempalates for creating copies of such modules on demand.”
A class is a collection of objects of similar type
Inheritance is the process by which objects of one class acquire the properties of objects of
another class.
Polymorphism, means the ability to take more than one form.
Dynamic binding (also known as late binding) means that the code associated with a given
procedure call is not known until the time of the call at run-time
Object-orientation contributes to the solution of many problems associated with the
development and quality of software products
Object-oriented programming incorporates all of object-based programming features along
with two additional features, namely, inheritance and dynamic binding
The most popular application of object-oriented programming, up to now, has been in the
area of user interface design such as windows
Questions:
1. Discuss features of OOPS
2. What do you mean by Dynamic Binding? How it is useful in OOPS
3. What are the Applications of OOPS
4. State characteristics of C++
UNIT I
Lesson 2
CLASS & OBJECT
Objective:
Class
Object
Now you have an idea what object oriented programming is. Here in this second lecture of OOP we
will go through some of the important terminologies used in OOP like class and object.
CLASS
A class is a logical method to organize data and functions in the same structure. They are declared
using keyword class, whose functionality is similar to that of the C keyword struct, but with the
possibility of including functions as members, instead of only data.
Its form is:
class class_name {
permission_label_1:
member1;
permission_label_2:
member2;
...
} object_name;
where class_name is a name for the class (user defined type) and the optional field object_name is
one, or several, valid object identifiers. The body of the declaration can contain members, that can
be either data or function declarations, and optionally permission labels, that can be any of these
three keywords: private:, public: or protected:. They make reference to the permission which the
following members acquire:
private members of a class are accessible only from other members of their same class or from their
"friend" classes.
protected members are accessible from members of their same class and friend classes, and also
from members of their derived classes.
Finally, public members are accessible from anywhere the class is visible.
If we declare members of a class before including any permission label, the members are considered
private, since it is the default permission that the members of a class declared with the class
keyword acquire.
For example:
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void);
} rect;
Declares class CRectangle and an object called rect of this class (type). This class contains four
members: two variables of type int (x and y) in the private section (because private is the default
permission) and two functions in the public section: set_values() and area(), of which we have only
included the prototype.
Notice the difference between class name and object name: In the previous example, CRectangle
was the class name (i.e., the user-defined type), whereas rect was an object of type CRectangle. Is
the same difference that int and a have in the following declaration:
int a;
int is the class name (type) and a is the object name (variable).
On successive instructions in the body of the program we can refer to any of the public members of
the object rect as if they were normal functions or variables, just by putting the object's name
followed by a point and then the class member (like we did with C structs).
For example:
rect.set_value (3,4);
myarea = rect.area();
but we will not be able to refer to x or y since they are private members of the class and they could
only be referred from other members of that same class. Confused? Here is the complete example of
class CRectangle:
// classes example
#include <iostream.h>
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void) {return (x*y);}
};
void CRectangle::set_values (int a, int b) {
x = a;
y = b;
}
int main () {
CRectangle rect;
rect.set_values (3,4);
cout << "area: " << rect.area();
}
Output :
area: 12
The new thing in this code is the operator :: of scope included in the definition of set_values(). It is
used to declare a member of a class outside it. Notice that we have defined the behavior of function
area() within the definition of the CRectangle class - given its extreme simplicity. Whereas
set_values() has only its prototype declared within the class but its definition is outside. In this
outside declaration we must use the operator of scope ::.
The scope operator (::) specifies the class to which the member being declared belongs, granting
exactly the same scope properties as if it was directly defined within the class. For example, in the
function set_values() of the previous code, we have referred to the variables x and y, that are
members of class CRectangle and that are only visible inside it and its members (since they are
private).
The only difference between defining a class member function completely within its class and to
include only the prototype, is that in the first case the function will automatically be considered
inline by the compiler, while in the second it will be a normal (not-inline) class member function.
The reason why we have made x and y private members (remember that if nothing else is said all
members of a class defined with keyword class have private access) it is because we have already
defined a function to introduce those values in the object (set_values()) and therefore the rest of the
program does not have a way to directly access them. Perhaps in a so simple example as this you do
not see a great utility protecting those two variables, but in greater projects it may be very important
that values cannot be modified in an unexpected way (unexpected from the point of view of the
object).
One of the greater advantages of a class is that we can declare several different objects from it. For
example, following with the previous example of class CRectangle, we could have declared the
object rectb in addition to the object rect :
// class example
#include <iostream.h>
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void) {return (x*y);}
};
void CRectangle::set_values (int a, int b) {
x = a;
y = b;
}
int main () {
CRectangle rect, rectb;
rect.set_values (3,4);
rectb.set_values (5,6);
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
}
Output
rect area: 12
rectb area: 30
Notice that the call to rect.area() does not give the same result as the call to rectb.area(). This is
because each object of class CRectangle has its own variables x and y, and its own functions
set_value() and area().
On that is based the concept of object and object-oriented programming. In that data and functions
are properties of the object, instead of the usual view of objects as function parameters in structured
programming. In this and the following sections we will discuss advantages of this methodology.
In this concrete case, the class (type of object) to which we were talking about is CRectangle, of
which there are two instances, or objects: rect and rectb, each one with its own member variables
and member functions.
Object
Definition (Object) An object is an instance of a class. It can be uniquely identified by its name and
it defines a state which is represented by the values of its attributes at a particular time.
The state of the object changes according to the methods which are applied to it. We refer to these
possible sequence of state changes as the behaviour of the object:
Definition (Behaviour) The behaviour of an object is defined by the set of methods which can be
applied on it.
We now have two main concepts of object-orientation introduced, class and object. Object-oriented
programming is therefore the implementation of abstract data types or, in more simple words, the
writing of classes. At runtime instances of these classes, the objects, achieve the goal of the program
by changing their states. Consequently, you can think of your running program as a collection of
objects.
MEMORY ALLOCATION FOR OBJECTS
We have stated that the memory space for objects is allocated when they are declared and not when
the class is specified. This statement is only partly true. Actually, the member functions are created
and placed in the memory space only once when they are defined as a part of a class specification.
Since all the objects belonging to that class use the same member functions, no separate space is
allocated for member functions when the objects are created. Only space for member variables is
allocated separately for each object. Separate memory locations for objects are essential, because the
member variables will hold different data values for different objects.
Common for all objects Member Function 1
Member Function 2
memory created when Function defined
Member Function 1 Member Function 1 Member Function 1
Member Function 2 Member Function 2 Member Function 2
Object 1 Object 2 Object 3Memory created
when Objects defined.
OBJECTS AS FUNCTION ARGUMENTS
Like any other data type, an object may be used as a function argument. This can be done in two
ways:
A copy of the entire object is passed to the function.
Only the address of the object is transferred to the function.
The first method is called pass-by-value. Since a copy of the object is passed to the function, any
changes made to the object inside the function do not affect the object used to call the function. The
second method is called pass-by-reference. When an address of the object is passed the called
function works directly on the actual object used in the call. This means that any changes made to
the object inside the function will reflect in the actual object. The pass-by reference method is more
efficient since it requires to pass only the address of the object and not the entire object.
Program illustrates the use of objects as function arguments. It performs the addition of time in the
hour and minutes format.
Example: Object as argument
#include<iostream.h>
class time
{
int hours;
int minutes;
public:
void gettime(int h, int m)
{
hours = h; minutes = m;
}
void puttime(void)
{
cout<<hours<<” hours and”;
cout<<minutes<<”minutes”<<”\n”;
}
void sum(time , time ); /declaration with objects as arguments
};
void time:: sum(time t1, time t2); //t1 & t2 are objects
{
minutes = t1.minutes + t2.minutes;
hours = minutes/60
minutes = minutes%60;
hours = hours + t1.hours + t2.hours;
}
int main()
{
time T1,T2,T3;
T1.gettime(2,45); //get T1
T2.gettime(3,30); //get T2
T3.sum(T1,T2); //T3=T1+T2
Cout<< “T1= “;T1.puttime(); //display T1
Cout<< “T2= “;T2.puttime(); //display T2
Cout<< “T3= “;T3.puttime(); //display T3
Return 0;
}
Output
T1 = 2 hours and 45 minutes
T2 = 3 hours and 30 minutes
T3 = 6 hours and 15 minutes
Since the member function sum( ) is invoked by the object T3, with the objects Tl and T2 as
arguments, it can directly access the hours and minutes variables ofT3. But, the members of Tl and
T2 can be accessed only by using the dot operator (like Tl.hours and T1.minutes). Therefore, inside
the function sum() the variables hours and minutes refer to T3, T1.hours and T1.minutes refer to Tl,
and T2.hours and T2.minutes refer to T2.
An object can also be passed. as an argument to a non-member function. However, such functions
can have access to the public member functions only through the objects passed as arguments to it.
These functions cannot have access to the private data members
Attribute
Definition( Attribute) A property of object. It cannot exist independently of the object. Attribute
may take other objects as values. It has a type. It describes the range of values that that property may
hold.
Method
Definition (Method) A method is associated with a class. An object invokes a method as a reaction
to receipt of a message.
A Method is a service that can be requested from any object of the Class to affect behavior. A
Method (Operation) can either be a command or a question. A question should never change the
state of the object only a command can. The outcome of the Operation depends on the current state
of the object.
Summary
A class is a logical method to organize data and functions in the same structure. They are
declared using keyword class
private members of a class are accessible only from other members of their same class or
from their "friend" classes.
protected members are accessible from members of their same class and friend classes, and
also from members of their derived classes.
public members are accessible from anywhere the class is visible.
An object is an instance of a class. It can be uniquely identified by its name and it defines a
state which is represented by the values of its attributes at a particular time.
The behaviour of an object is defined by the set of methods which can be applied on it.
Attribute: A property of object. It cannot exist independently of the object.
A method is associated with a class. An object invokes a method as a reaction to receipt of a
message.
Questions
1. Distinguish between Class and Object
2. Define
a) Method
b) Attribute.
UNIT I
Lesson 3
C++ GETTING STARTED
Objective
Token
Datatype
Header files
Operators
As you know that C++ is extension of C , most of its features, data types , operator set are very
much similar to C in syntax and constructs. Here in this lecture we will discuss differences in them
TOKENS
The smallest unit in a program is known as a token. C++ has the following tokens .
Keywords
Identifiers
Constants Strings
Operators
KEYWORDS
Keywords are reserved words that cannot be useds as names for the program variables or other user
defined program entities. Compared to C, C++ has more keywords as specified below
asm Double new switch
auto Else operator template
break Enum private this
case Extern protected throw
catch Float public try
char For register typedef
class Friend return union
const Goto short unsigned
continue If signed virtual
default Inline sizeof void
delete Int static volatile
do Long struct while
IDENTIFIERS
Identifier is the name given to variables, functions, arrays, classes, user defined types etc. The
naming convention in C++ is similar to C language. The rules are described below
. The name starts with an alphabetic character and not with a digit.
. A name can contain alphabets, digits and underscore characters.
. Names are case sensitive that is uppercase and lowercase letters are different.
. A keyword cannot be used as a name for a variable.
DATA TYPES
The basic data type in C language is supported in C++. C++ has four basic built-in data types. They
are char, int, float and double. Char is for storing a single character and is usually one byte in size.
Int stores an integral value u two bytes long. Float and double store floating point numbers. Float is
for single precision numbers and double is for double precision floating points. Signed and unsigned
are modifiers that can be used with any integral type. Th type is signed by default.
C++ recognizes the data type shown in the table below.
Type Name Bytes Range of Valueschar 1 -128 to 127
unsigned char 1 0 to 255
Signed char 1 -128 to 127
int 2 -32768 to 32767
unsigned int 2 0 to 65535
signed int 2 -32768 to 32767
short int 2 -32768 to 32767
Unsigned short int 2 0 to 65535
Signed short int 2 -32768 to 32767
Long int 4 -2147483648 to 2147483647
signed long int 4 -2147483648 to 2147483647
Unsigned long i.nt 4 0 to 4294967295
float 4 3.4E-38 to 1.7E+38
double 8 1.7E-308 to 1.7E+308
long double 10 3.4E-4932 to 1.1 E+4932
SPECIFIERS
Specifiers modify the meaning of the basic built-in types. They effectively provide a larger set of
built in types. T specifiers, or qualifiers, are short, long, signed, and unsigned. The long and short
specifiers set the range that tt type will hold. Short int, int, and long int are in ascending order of
range size. The actual values vary from mac machine. Similarly, float; double, and long double are
in order of increasing capacity. There is no long float and n float or double. The signed and unsigned
specifiers indicate whether the first bit of the data type is to be used a~ indicator or not. Except for
charthe default is signed. Char mayor may not be signed by default. The following pi shows the
bytes used by the different data types along with the specifiers:
#include <iostream.h> II Header required for cout.
void main()
int i;
unsigned int ui;
short si; // int is understood
long i; //ditto
unsigned short usi; //ditto
unsigned long uli; //ditto
char c;
unsigned char uc;
float f;
double d;
long double Id;
//cout is Console out similar to printf
cout<<”\nSize of int = “<<sizeof(i);
cout<<”\nSize of unsigned int = "<<sizeof(ui);
cout«"\nSize of short int = "<<sizeof(si);
cout<<"\nSize of long int = "<<sizeof(li);
cout<<”\nSize of unsigned short int = "<<sizeof(usi);
cout<<”\nSize of unsigned long int = "<<sizeof(uli)<<"\n";
cout<<"\nSize of char = "<<sizeof(c);
cout<<"\nSize of unsigned char = "<<sizeof(uc)<<"\n";
cout<<"\nSize of float = "<<sizeof(f);
cout<<"\nSize of double = "<<sizeof(d); cout<<''\nSize of long double = "<<sizeof(ld)<<''\n'';
ESCAPE SEQUENCES
The escape sequences allow you to use a sequence of characters to represent special characters.
Escape sequences are listed below. These escape sequences are used in I/O statements like
printf(), scanf(), cout etc.
Sequence Name
\a Alert (bell)
\f Formfeed
\r Carriaqe return
\v Vertical tab
\' Sinqle quotation mark
\\ Backslash
\b Backspace
\n Newline
\t Horizontal tab
\? Literal quotation mark
HEADER FILES
All the header files available in C are used in C++, alongwith other header files of C++. A few of
them are in the table.
FileName Major Contents
ASSERT.H Assert debugging macro
BIOS.H IOS service functions
CDERR.H Common dialog error return codes
COLORDLG.H Common dialog color dialog's control id numbers
COMMDLG.H Common dialog functions, types, and definitions
CONIO.H Console and port I/O routines
CPL.H Control panel extension DLL definitions
CTYPE.H Character classification
CUSTCNTL.H Custom Control Library header file
DDE.H Dynamic Data Exchange structures and definitions
DDEML.H DDEML API header file
DIRECT.H Directory control
DOS.H MS-DOS interface functions
ERRNO.H errno variable definitions
FSTREAM.H Functions used by the filebuf and fstream classes
GRAPH.H Low-level graphics and font routines
IO.H File-handling and low-level I/O
IOMAINP.H definitions / declarations for iostream's parameterized
manipulators
IOS.H Functions used by the ios class
IOSTREAM.H Functions used by the iostream classes
ISTREAM,H Functions used by the istream class
MALLOC.H Memory-allocation functions
MATH.H Floating-point-math routines
MEMORY.H Buffer-manipulation routines
MMSYSTEM.H I NEW.H Include file for Multimedia APls.
OLE.H OLE functions, types, and definitions
NEW.H Declarations and definitions for C++ memory allocation
functions.
OSTREAM.H Functions used by the ostream class
PENWIN.H Pen Windows functions, types, and definitions
PENWOEM.H Pen Windows APls into recognizer layer
PGCHART.H Presentation graphics
PRINT.H Printing helper functions, types, and definitions
PROCESS.H Process-control routines
SCRNSAVE.H Win3.1 screensaver defines and definitions
SSEARCH.H Searching & sorting functions
SETJMP.H Setjmp and longjmp functions
SHARE.H Flags used in _sopen
SHELLAPI.H SHELL.DLL functions, types, and definitions
SIGNAL.H Constants used by signal function
STDARG.H Macros for variable-length argument-list functions
STDDEF.H Commonly used data types and values
STDIO.H Standard I/O header file
STDIOSTR.H Functions used by the stdiostream and stdiobuf classes
STDLlB.H Commonly used library functions
STREAMB.H Functions used by the streambuf class
STRESS.H Stress functions definitions
STRING.H string manipulation function
STRSTREA.H Functions used by strstream classes
TIME.H General time functions
VER.H Version mngt. functions, types and definitions
VMEMORY.H Virtual memory functions
WFEXT.H Windows File Manager Extensions definitions
PREPROCESSOR DIRECTIVES
The table below lists the directives to the preprocessor. Their usage and the meaning in C++ is the
same as in any details regarding usage, please refer to any C reference material..
#define
#error
#include
#else
#ifdef
#elif
#pragma
#if
#Iine
#endif
#ifndef
#undef
FILE EXTENSIONS
In C++. all the programs carry ".CPP" extensions as compared to ".C" extensions in C. Anyway,
even if you al working with a C++ compiler and give" .C" extension, C compiler takes over to
compile that program.
C++ COMMENTS
1. /* *1 comment is used to apply mutiline comment, where' 1*' begins a comment and' *1 . ends it.
2. Double-slash (II) sequence is used to comment single line completely.
OPERATORS:
The table below lists C and C++ operators by category.
C++ introduced many operators compared to C. This is described below
Scope resolution operator:
As C language does not allow the global variable value to be accessed from the inner block having
the same variable name as the global variable in order to solve this conflict the scope resolution
operator is used. The example presented below
#include <iostream.h>
int gl =10; // global variable gl
main()
int gl = 20; // gl redeclared again, local to main
int k = gl;
int gl = 30; // gl declared again in inner block
cout << "\n we are in inner block: \n";
cout << "k = " << k << "\n"; cout << "gl = " << gl << ''\n'';
cout << ":: gl = " << ::gl << ''\n'';
cout<< "\n We are in outer block: \n";
cout << "gl = " << gl << ''\n''; cout<< "::gl = " << ::gl << ''\n'';
The output is
we are in inner block:
k=20
g1=30
::gl=10
we are in outer block
gl=20
::gl =10
In the program above gl variable is declared three times with different scope and uses the :: scope
resolution operator to access the global version as shown in the output.
MEMBER DEREFERENCING OPERATOR
The types of member referencing operators are described below
::* Pointer to member declerator
->* Pointer to member operator
.* Pointer to member operator
This operator is used in context with pointer to object member.
MEMORY MANAGEMENT OPERATOR
In c++ two important memory management operators are described below
delete Memory release operator
new Memory allocation operator
The general format of usage is
Pointer-variable = new data-type
Where Pointer-variable is used to hold the address of variable of data-type; Data-type is used to
specify any valid data. The new operator is used to allocate sufficient memory to hold a data object
of type data-type and returns the address of the object to pointer variable. Few examples are given
below
int *ptr ;.
ptr = new int;
Other formats are
Pointer-variable = new data-type(value)
Where value is the initial value assigned to Pointer-variable. Few examples are given below
int *ptr = new int(25);
assign value 25 to ptr variable
You can create an array using the new operator as specified in the general format below
Pointer-variable = new data-type[size];
Where size is the required size of the memory to be allocated. Examples are given below
int * Arrptr = new int[3][4];
To release the memory allocated using the new operator, delete operator is used. To delete memory
allocated us the pointer holding the address of the allocated memory. Examples are given below
delete p; // to delete the memory area pointed by p.
delete [4] q; // deletes 4 elements from the array
delete [ ] p; // deletes the entire array
You can delete number of element from the array which is specified in the square bracket as
specified in the second example above.
MANIPULATORS
It is an operator used to format the presentation of data. This means that you can arrange the data on
the screen in a desired format. The most common manipulators are
endl Line Feed operator equivalent to special character' \n '
setw Field Width operator used to specify the display width of data on the screen.
TYPE CAST OPERATOR
The type cast operator has similar functionality to C language. The syntax has changed as explained
in the example below
In C languageAverage = sum /(float)i;
In C++ language
Average = sum / float (i);
Arithmetic
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulus
Relation
< Less than
<= Less than or equal to
> Greater than
>= Greater than or equal to
-- Equal
!= Not equal
Assignment
= Assignment
+= Addition
- Subtraction
/= Division
<<= Left shift
assignment
&= Bitwise AND
|= Bitwise OR
Bitwise Logical
& Bitwise AND
&& Logical AND
|| Logical OR
/\ Bitwise-exclusive- OR
! Logical NOT
| Bitwise OR
<< Left shift
>> Right shift
~ One's complement Pointer Conditional
& Address of ? : Ternary
* Indirection
Miscellaneous: C++ Only
( ) Function call
:: Scope resolution
[ ] Array element & Reference
-> Pointer to structure member
.* Pointer to member
->* Pointer to member
. (type) Type cast sizeof() Size in bytes
The mathematical operators +, -, *, /, = all work in the same way, in mathematics and in C. Some
are evaluated I others in an expression, and are said to have higher precedence than the latter. The
unary operators are the ++ a - operators. They can be used before or after a variable and are
accordingly called pre or post increment or pre ( decrement operators. When used before a variable
the operation is first performed on the variable and then it i: in the expression. Conversely, when
used after a variable, the variable is first used in the expression and the incremented. For example
look at run the following program.
Program:
#include <iostream.h>
void main()
int i=10;
cout<<''\n post-increment i = "«i++;
cout<<''\n pre-increment i = "<<++i;
cout<<''\npost-decrement i = "<<i--;
cout<<''\npre-decrement i = "<<--i;
Output:
post-increment i = 10
pre-increment i = 12
post-decrement i = 12
pre-decrement i = 10
CONSTANTS
The const keyword specifies that a variable's value is constant and tells the compiler to prevent the
programmer from modifying it.
Example:
const int i = 5;
i = 10; // Error
i++; // Error
You can define constant using the #define, but the constant defined using const keyword is typed
check where as #define constant has no type information.
C++ uses const keyword to declare a constant pointer of two types
Constant pointer
char. const ptr1 = "GOOD"; II constant pointer
which means you cannot modify the address that ptr1 is initialized to
Pointer to a constant
int const .ptr2 = &m; // pointer to a constant
Which means that you cannot change the value at the address ptr2.
You can also declare both the pointer and the variable as constants in the following way
const char.const cp = "xyz";
ENUMERATED DATA TYPE
An enumerated data type is a user defined data type which provides a way to attach names to a
number which helps you to remember the number.
The syntax is similar to struct in C. For examples
enum shape{ circle,square,triangle};
Here shape is a user defined type which is used to declare a variable of type shape which can take
only the value
specified in the curly braces. The names in the curly braces represent the number 0 as circle,
1 as square, 2 as triangle automatically. ThedefauJt numbering starts from 0.
To declare variable conics of type shape
shape conics;
You can assign values in conics in following ways
conics = circle; // to assign 0 to conics
conics = 0; //it is not allowed and Error in C++
conics= (shape) 0; // correct way to assign using cast operator. '
int a = circle; // it is allowed.
STRUCT AND UNION
You can use struct and union to define user-defined type similar to C language along with function
prototype in the structure.
DECLARATION OF VARIABLES
Unlike C language you can declare variable at any position inside the function but before using the
variable. n program below demonstrates this feature.
#include <iostream.h>
void main()
float x; //declaration
float sum;
for(int count = 1; count < 10;count++)
cin>> x;
sum = sum + x;
float average; //declaration
average = sum / count; //declaration
cout« average;
}
The above program declares the variables and total at the beginning of the program and the variable
average i: declared in ttie middle of the program. Such a creation helps to declare a variable with
dynamic initialization; shown in the program above. The average variable is initialized with'
sum/count '.
Summary
The smallest unit in a program is known as a token. C++ has the following tokens .
KeywordsIdentifiers
Constants Strings
Operators
Keywords are reserved words that cannot be useds as names for the program variables or other
user defined program entities
Identifier is the name given to variables, functions, arrays, classes, user defined types etc.
The basic data type in C language is supported in C++. C++ has four basic built-in data types.
They are char, int, float and double
Float and double store floating point numbers
Specifiers modify the meaning of the basic built-in types. They effectively provide a larger set of
built in types.
The escape sequences allow you to use a sequence of characters to represent special characters.
In C++. all the programs carry ".CPP" extensions as compared to ".C" extensions in C
As C language does not allow the global variable value to be accessed from the inner block
having the same variable name as the global variable in order to solve this conflict the scope
resolution operator is used
To release the memory allocated using the new operator, delete operator is used.
The mathematical operators +, -, *, /, = all work in the same way, in mathematics and in C.
The const keyword specifies that a variable's value is constant and tells the compiler to prevent
the programmer from modifying it.
An enumerated data type is a user defined data type which provides a way to attach names to a
number which helps you to remember the number.
Question
What is token? Explain.
Explain the term Datatype, scope Resolution Operator, Enumerated Data Type
Give various types of operator set in C++
UNIT I
LESSON 4
FUNCTIONS IN C++
Objective
In this lesson You will get acquainted with an important concept of OOPS i.e.
Functions,
Call by value,
Call by reference,
Friend function .
“In the previous section we have seen how a class is implemented along with the usage of objects and its subsequent components. Now comes the most important building block of the program…. Function. You will understand how important role a Function plays in program through the sessions below. ”
FUNCTION IN C++
Using functions you can structure your programs in a more modular way, accessing all the potential
that structured programming in C++ can offer us.
A function is a block of instructions that is executed when it is called from some other point of the
program. The following is its format:
type name ( argument1, argument2, ...) statement
where:
· type is the type of data returned by the function.
· name is the name by which it will be possible to call the function.
· arguments (as many as wanted can be specified). Each argument consists of a type of data
followed by its identifier, like in a variable declaration (for example, int x) and which acts within
the function like any other variable. They allow passing parameters to the function when it is called.
The different parameters are separated by commas.
· statement is the function's body. It can be a single instruction or a block of instructions.
In the latter case it must be delimited by curly brackets {}.
function example:
// function example
#include <iostream.h>
int addition (int a, int b)
{
int r;
r=a+b;
return (r);
}
int main ()
{
int z;
z = addition (5,3);
cout << "The result is " << z;
return 0;
}
output
The result is 8
Function addition declares a new variable (int r;), and by means of the expression r=a+b;, it
assigns to r the result of a plus b. Because the passed parameters for a and b are 5 and 3
respectively, the result is 8.
The following line of code:
return (r);
finalizes function addition, and returns the control back to the function that called it (main)
following the program from the same point at which it was interrupted by the call to addition. But
additionally, return was called with the content of variable r (return (r);), which at that moment
was 8, so this value is said to be returned by the function.
And here is another example about functions:
// function example
#include <iostream.h>
int subtraction (int a, int b)
{
int r;
r=a-b;
return (r);
}
int main ()
{
int x=5, y=3, z;
z = subtraction (7,2);
cout << "The first result is " << z << '\n';
cout << "The second result is " << subtraction (7,2) << '\n';
cout << "The third result is " << subtraction (x,y) << '\n';
z= 4 + subtraction (x,y);
cout << "The fourth result is " << z << '\n';
return 0;
}
The first result is 5The second result is 5The third result is 2The fourth result is 6
Arguments passed by value and by reference..
Until now, in all the functions we have seen, the parameters passed to the functions have been
passed by value. This means that when calling a function with parameters, what we have passed to
the function were values but never the specified variables themselves. For example, suppose that we
called our first function addition using the following code :
int x=5, y=3, z;
z = addition ( x , y );
What we did in this case was to call function addition passing the values of x and y, that means 5
and 3 respectively, not the variables themselves.
This way, when function addition is being called the value of its variables a and b become 5 and 3
respectively, but any modification of a or b within the function addition will not affect the values
of x and y outside it, because variables x and y were not passed themselves to the the function, only
their values.
But there might be some cases where you need to manipulate from inside a function the value of an
external variable. For that purpose we have to use arguments passed by reference, as in the function
duplicate of the following example:
// passing parameters by reference
#include <iostream.h>
void duplicate (int& a, int& b, int& c)
{
a*=2;
b*=2;
c*=2;
}
int main ()
{
int x=1, y=3, z=7;
duplicate (x, y, z);
cout << "x=" << x << ", y=" << y << ", z=" << z;
return 0;
}
output
x=2, y=6, z=14
The first thing that should call your attention is that in the declaration of duplicate the type of each
argument was followed by an ampersand sign (&), that serves to specify that the variable has to be
passed by reference instead of by value, as usual.
When passing a variable by reference we are passing the variable itself and any modification that we
do to that parameter within the function will have effect in the passed variable outside it.
To express it another way, we have associated a, b and c with the parameters used when calling the
function (x, y and z) and any change that we do on a within the function will affect the value of x
outside. Any change that we do on b will affect y, and the same with c and z.
That is why our program's output, that shows the values stored in x, y and z after the call to
duplicate, shows the values of the three variables of main doubled.
If when declaring the following function:
void duplicate (int& a, int& b, int& c)
we had declared it thus:
void duplicate (int a, int b, int c)
that is, without the ampersand (&) signs, we would have not passed the variables by reference, but
their values, and therefore, the output on screen for our program would have been the values of x, y
and z without having been modified.
Passing by reference is an effective way to allow a function to return more than one single value. For
example, here is a function that returns the previous and next numbers of the first parameter passed.
FRIENDLY FUNCTIONS
I
We have been emphasizing throughout this chapter that the private members cannot accessed from
outside the class. That is, a non-member function cannot have an access to private data of a class.
However, there could be a situation where we would like two classes to share a particular function.
For example, consider a case where two classes, manager if scientist, have been defined. We would
like to use a function income_tax( ) to operate the objects of both these classes. In such situations,
C++ allows the common function made friendly with both the classes, thereby allowing the function
to have access to private data of these classes. Such a function need not be a member of any of these
classes.
To make an outside function “friendly” to a class, we have to simply declare this function as a friend
of the class as shown below
Class ABC
{
……..
……..
public:
……..
……..
friend void xyz(void); //declaration
};
The function declaration should be preceded by the keyword friend. The function is defined Else
here in the program like a normal C++ function. The function definition does not "either the
keyword friend or the scope operator ::. The functions that are declared with thekeyword friend are
known as friend functions. A function can be declared as a friend in anynumber of classes. A friend
function, although not a member function has full access rights to the private members of the class.
Certain special characteristics of friend function :
It is not in the scope of the class to which it has been declared as friend.
Since it is not in the scope of the class, it cannot be called using the object of that class.
It can be invoked like a normal function without the help of any object.
Unlike member functions, it cannot access the member names directly and has to object
name and dot membership operator with each member name.( e.g. A.x).
It can be declared either in the public or the private part of a class without affecting its
meaning.
Usually, it has the objects as arguments.
Example : Friend Function
#include <iostream>
using namespace std;
class sample
{
int a;
int b;
public :
void setvalue( )
{
a=25; b= 40;
}
friend float mean(sample s);
} ;
float mean(samp1e s)
{
return f1oat(s.a + s.b)/2.0;
int main( )
{
sample x; // object X
x.setva1ue( );
cout <<” Mean value = “ << mean (x) « “\n”;
return 0;
The output of Program
Mean value = 32.5
The friend function accesses the class variables a and b by using the dot operator and the object
passed to it. The function call mean(x) passes the object x by value to the friend function.
Member functions of one class can be friend functions of another class. In such cases, they are
defined using the scope resolution operator, which is shown as follows:
c1ass x
{
………
………
int fun1( ); // member function of X
………
};
class Y
{
……..
………
friend int X :: funl( ); // funl () of X
…….. // is friend of y
};
The function funl( ) is a member of class X and a friend of class Y.
We can also declare all the member functions of one class as the mend functions of anotlt class. In
such cases, the class is called a friend class. This can be specified as follows:
class Z
{
……….
friend class X; // all member functions of X are
//friends to Z
};
program demonstrates how mend functions work as a bridge between the classes.
#include <iostream>
using namespace std;
class ABC; //forward declaration
class XYZ
{
int x;
public :
void setvalue(int i)
{
x = i;
}
friend void max(XYZ, ABC);
};
class ABC
{
int a;
public :
void setvalue(int i)
{
x = i;
}
friend void max(XYZ, ABC);
};
void max(XYZ m, ABC n) //definition of friend
{
if(m.x >= n.a)
cout<<m.x;
else
cout<<n.a;
}
int main( )
{
ABC abc;
Abc.setvalue(10);
XYZ xyz;
xyz.setvalue(20);
max(xyz, abc);
return 0;
}
output
20
The function max( ) has arguments from both XYZ and ABC. When the function max( ) is declared
as a friend in XYZ for the first time, the compiler will not acknowledge the presence of ABC unless
its name is declared in the beginning as
class ABC;
This is known as 'forward' declaration.
As pointed out earlier, a friend function can be called by reference. In this case, local copies of the
objects are not made. Instead, a pointer to the address of the object is passed and the called function
directly works on the actual object used in the call.
This Method can be used to alter the values of the private member of a class. Remember, altering
the values of private members is against the basic principles of data hiding. It should be used only
when absolutely necessary.
Summary
A function is a block of instructions that is executed when it is called from some other point
of the program.
Passing by reference is an effective way to allow a function to return more than one single
value.
C++ allows the common function made friendly with both the classes, thereby allowing the
function to have access to private data of these classes. Such a function need not be a
member of any of these classes.
Questions
1.What is friend function? Explain it’s characteristic
2.state the merits and demerits of friend function
3..How member function of a class is defined?
3. point ot errors in the following program if any
void main()
{
int a=30;
f();
}
void f()
{
int b=20;
}
UNIT I
Lesson 5
CONTROL STRUCTURES :
Objective
After getting an idea what function is, today we will discuss commonly used control structures of
programming language such as
if and else
The while loop.
The do-while loop.
The for loop.
The break instruction.
The selective Structure: switch.
A program is usually not limited to a linear sequence of instructions. During its process it may
bifurcate, repeat code or take decisions. For that purpose, C++ provides control structures that serve
to specify what has to be done to perform our program.
With the introduction of control sequences you are going to have an introduction to a new concept:
the block of instructions. A block of instructions is a group of instructions separated by semicolons
(;) but grouped in a block delimited by curly bracket signs: { and }.
Most of the control structures that you will see in this section allow a generic statement as a
parameter, this refers to either a single instruction or a block of instructions, as we want. If we want
the statement to be a single instruction we do not need to enclose it between curly-brackets ({}). If
you want the statement to be more than a single instruction you must enclose them between curly
brackets ({}) forming a block of instructions.
Conditional structure: if and else
It is used to execute an instruction or block of instructions only if a condition is fulfilled. Its form is:
if (condition) statement
where condition is the expression that is being evaluated. If this condition is true, statement is
executed. If it is false, statement is ignored (not executed) and the program continues on the next
instruction after the conditional structure.
For example, the following code fragment prints out x is 100 only if the value stored in variable x
is indeed 100:
if (x == 100)
cout << "x is 100";
If we want more than a single instruction to be executed in case that condition is true we can
specify a block of instructions using curly brackets { }:
if (x == 100)
{
cout << "x is ";
cout << x;
}
We can additionally specify what we want that happens if the condition is not fulfilled by using the
keyword else. Its form used in conjunction with if is:
if (condition) statement1 else statement2
For example:
if (x == 100)
cout << "x is 100";
else
cout << "x is not 100";
prints out on the screen x is 100 if indeed x is worth 100, but if it is not -and only if not- it prints
out x is not 100.
The if + else structures can be concatenated with the intention of verifying a range of values. The
following example shows its use telling if the present value stored in x is positive, negative or none
of the previous, that is to say, equal to zero.
if (x > 0)
cout << "x is positive";
else if (x < 0)
cout << "x is negative";
else
cout << "x is 0";
Remember that in case we want more than a single instruction to be executed, we must group them
in a block of instructions by using curly brackets { }.
Repetitive structures or loops
Loops have as objective to repeat a statement a certain number of times or while a condition is
fulfilled.
The while loop.
Its format is:
while (expression) statement
and its function is simply to repeat statement while expression is true.
For example, we are going to make a program to count down using a while loop:
// custom countdown using while
#include <iostream.h>
int main ()
{
int n;
cout << "Enter the starting number > ";
cin >> n;
while (n>0) {
cout << n << ", ";
--n;
}
cout << "FIRE!";
return 0;
}
output
Enter the starting number > 88, 7, 6, 5, 4, 3, 2, 1, FIRE!
When the program starts the user is prompted to insert a starting number for the countdown.
Then the while loop begins, if the value entered by the user fulfills the condition n>0 (that n
be greater than 0 ), the block of instructions that follows will execute an indefinite number of
times while the condition (n>0) remains true.
All the process in the program above can be interpreted according to the following script:
beginning in main:
1. User assigns a value to n.
2. The while instruction checks if (n>0). At this point there are two possibilities:
o true: execute statement (step 3,)
o false: jump statement. The program follows in step 5..
3. Execute statement:cout << n << ", ";
--n;
(prints out n on screen and decreases n by 1).
4. End of block. Return Automatically to step 2.
5. Continue the program after the block: print out FIRE! and end of program.
We must consider that the loop has to end at some point, therefore, within the block of
instructions (loop's statement) we must provide some method that forces condition to
become false at some moment, otherwise the loop will continue looping forever. In this case
we have included --n; that causes the condition to become false after some loop
repetitions: when n becomes 0, that is where our countdown ends.
Of course this is such a simple action for our computer that the whole countdown is
performed instantly without practical delay between numbers.
The do-while loop.
Format:
do statement while (condition);
Its functionality is exactly the same as the while loop except that condition in the do-while
is evaluated after the execution of statement instead of before, granting at least one
execution of statement even if condition is never fulfilled. For example, the following
program echoes any number you enter until you enter 0.
// number echoer
#include <iostream.h>
int main ()
{
unsigned long n;
do {
cout << "Enter number (0 to end): ";
cin >> n;
cout << "You entered: " << n << "\n";
} while (n != 0);
return 0;
}
output
Enternumber(0toend):12345Youentered:12345Enternumber(0toend):160277Youentered:160277Enternumber(0toend):0You entered:0
The do-while loop is usually used when the condition that has to determine its end is
determined within the loop statement, like in the previous case, where the user input within
the block of intructions is what determines the end of the loop. If you never enter the 0 value
in the previous example the loop will never end.
The for loop.
Its format is:
for (initialization; condition; increase) statement;
and its main function is to repeat statement while condition remains true, like the while
loop. But in addition, for provides places to specify an initialization instruction and an
increase instruction. So this loop is specially designed to perform a repetitive action with a
counter.
It works the following way:
1, initialization is executed. Generally it is an initial value setting for a
counter varible. This is executed only once.
2, condition is checked, if it is true the loop continues, otherwise the loop
finishes and statement is skipped.
3, statement is executed. As usual, it can be either a single instruction or a
block of instructions enclosed within curly brackets { }.
4, finally, whatever is specified in the increase field is executed and the loop
gets back to step 2.
Here is an example of countdown using a for loop.
// countdown using a for loop
#include <iostream.h>
int main ()
{
for (int n=10; n>0; n--) {
cout << n << ", ";
}
cout << "FIRE!";
return 0;
}
output 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE!
The initialization and increase fields are optional. They can be avoided but not the
semicolon signs among them. For example we could write: for (;n<10;) if we want to
specify no initialization and no increase; or for (;n<10;n++) if we want to include
an increase field but not an initialization.
Optionally, using the comma operator (,) we can specify more than one instruction in any of
the fields included in a for loop, like in initialization, for example. The comma operator
(,) is an instruction separator, it serves to separate more than one instruction where only one
instruction is generally expected. For example, suppose that we wanted to intialize more than
one variable in our loop:
for ( n=0, i=100 ; n!=i ; n++, i-- )
{
// whatever here...
}
This loop will execute 50 times if neither n nor i are modified within the loop:
n starts with 0 and i with 100, the condition is (n!=i) (that n be not equal to i). Beacuse n is
increased by one and i decreased by one, the loop's condition will become false after the
50th loop, when both n and i will be equal to 50.
Bifurcation of control and jumps.
The break instruction.
Using break we can leave a loop even if the condition for its end is not fulfilled. It can be
used to end an infinite loop, or to force it to end before its natural end. For example, we are
going to stop the count down before it naturally finishes (an engine failure maybe):
// break loop example
#include <iostream.h>
int main ()
{
int n;
for (n=10; n>0; n--) {
cout << n << ", ";
if (n==3)
{
cout << "countdown aborted!";
break;
}
}
return 0;
}
output
10, 9, 8, 7, 6, 5, 4, 3, countdown aborted
The continue instruction.
The continue instruction causes the program to skip the rest of the loop in the present
iteration as if the end of the statement block would have been reached, causing it to jump to
the following iteration. For example, we are going to skip the number 5 in our countdown:
// break loop example
#include <iostream.h>
int main ()
{
for (int n=10; n>0; n--) {
if (n==5) continue;
cout << n << ", ";
}
cout << "FIRE!";
return 0;
}10, 9, 8, 7, 6, 4, 3, 2, 1, FIRE!
The goto instruction.
It allows making an absolute jump to another point in the program. You should use this
feature carefully since its execution ignores any type of nesting limitation.
The destination point is identified by a label, which is then used as an argument for the goto
instruction. A label is made of a valid identifier followed by a colon (:).
This instruction does not have a concrete utility in structured or object oriented programming
aside from those that low-level programming fans may find for it. For example, here is our
countdown loop using goto:
// goto loop example
#include <iostream.h>
int main ()
{
int n=10;
loop:
cout << n << ", ";
n--;
if (n>0) goto loop;
cout << "FIRE!";
return 0;
}
Output
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, FIRE
The exit function.
exit is a function defined in cstdlib (stdlib.h) library.
The purpose of exit is to terminate the running program with an specific exit code. Its
prototype is:
void exit (int exit code);
The exit code is used by some operating systems and may be used by calling programs. By
convention, an exit code of 0 means that the program finished normally and any other
value means an error happened.
The selective Structure: switch.
The syntax of the switch instruction is a bit peculiar. Its objective is to check several possible
constant values for an expression, something similar to what we did at the beginning of this section
with the linking of several if and else if sentences. Its form is the following:
switch (expression) { case constant1: block of instructions 1
break; case constant2: block of instructions 2
break; . . . default: default block of instructions
}
It works in the following way: switch evaluates expression and checks if it is equivalent to
constant1, if it is, it executes block of instructions 1 until it finds the break keyword, then
the program will jump to the end of the switch selective structure.
If expression was not equal to constant1 it will check if expression is equivalent to constant2.
If it is, it will execute block of instructions 2 until it finds the break keyword.
Finally, if the value of expression has not matched any of the previously specified constants (you
may specify as many case sentences as values you want to check), the program will execute the
instructions included in the default: section, if this one exists, since it is optional.
Both of the following code fragments are equivalent:
switch example
switch (x) {
case 1:
cout << "x is 1";
break;
case 2:
cout << "x is 2";
break;
default:
cout << "value of x unknown";
}
if-else equivalent
if (x == 1) {
cout << "x is 1";
}
else if (x == 2) {
cout << "x is 2";
}
else {
cout << "value of x unknown";
}
We have mentioned before that the syntax of the switch instruction is a bit peculiar. Notice the
inclusion of the break instructions at the end of each block. This is necessary because if, for
example, we did not include it after block of instructions 1 the program would not jump to the
end of the switch selective block (}) and it would continue executing the rest of the blocks of
instructions until the first appearance of the break instruction or the end of the switch selective
block. This makes it unnecessary to include curly brackets { } in each of the cases, and it can also
be useful to execute the same block of instructions for different possible values for the expression
evaluated. For example:
switch (x)
{
case 1:
case 2:
case 3:
cout << "x is 1, 2 or 3";
break;
default:
cout << "x is not 1, 2 nor 3";
}
Notice that switch can only be used to compare an expression with different constants. Therefore
we cannot put variables (case (n*2):) or ranges (case (1..3):) because they are not valid
constants.
If you need to check ranges or values that are not constants use a concatenation of if and else if
sentences.
Summary
C++ provides control structures that serve to specify what has to be done to perform our
program.
If & else is used to execute an instruction or block of instructions only if a condition is
fulfilled
The if + else structures can be concatenated with the intention of verifying a range of values
Loops have as objective to repeat a statement a certain number of times or while a condition
is fulfilled.
The do-while loop is usually used when the condition that has to determine its end is
determined within the loop statement, like in the previous case, where the user input within
the block of instructions is what determines the end of the loop
Using break we can leave a loop even if the condition for its end is not fulfilled
The continue instruction causes the program to skip the rest of the loop in the present
iteration as if the end of the statement block would have been reached, causing it to jump to
the following iteration
Switch objective is to check several possible constant values for an expression, something
similar to what we did at the beginning of this section with the linking of several if and else if
sentences
Questions
1.Discus various control structure available in C++
2.Explain implementation of switch statement with syntax and example
write a program to print following using for loop
1
22
333
444
5555
UNIT I
Lesson 6
REPRESENTATION OF ABSTRACT DATA TYPES & SCOPE OF ATTRIBUTES
Objective
Concept of abstraction
Abstract Data type.
Designing an Abstract type
Choice of representation
Uptil now you have learned some basic concepts like operator set, control structure etc. now lets
have a look to the advanced feature of object oriented programming. One of them is abstract data
tpye. Here in this chapter I will explain its concept along with examples.
The Concept of Abstraction
The concept of abstraction is fundamental in programming
Two kinds of abstraction: process abstraction and data abstraction
Nearly all programming languages support process abstraction with subprograms
Nearly all programming languages designed since 1980 have supported data abstraction with
some kind of module
Introduction to Data Abstraction
Abstract data type: an encapsulation that includes only the data representation of one
specific data type and the subprograms that provide the operations for that type.
Built-in types are abstract data types Example: floating-point types
Actual format of the data value is hidden (users cannot directly manipulate actual
representation)
The only operations available are those provided by the language (users cannot create new
operations)
User-defined abstract data types must have the same characteristics as built-in abstract data
types
An Example
ADT for a stack
Abstract operations
Queue ADT
create(stack) /* create (allocate storage) and possible initialize */
destroy(stack) /* dealloacte storage */
empty(stack) /* predicate */
push(stack, element) /* push element */
pop(stack) /* remove top element */
top(stack) /* returns a copy of top element */
Implementation of stack can be changed (e.g., from array to linked list) without
changing the client code.
Abstract Data Types in C++
Since it is based on object-oriented programming, it supports ADTs by classes.
ADTs allows the creation of instances with well-defined properties and behaviour. In object-
orientation ADTs are referred to as classes. Therefore a class defines properties of objects which
are the instances in an object-oriented environment.
ADTs define functionality by putting main emphasis on the involved data, their structure,
operations as well as axioms and preconditions. Consequently, object-oriented programming is
``programming with ADTs'': combining functionality of different ADTs to solve a problem.
Therefore instances (objects) of ADTs (classes) are dynamically created, destroyed and used.
Encapsulation
o Data members and member functions
o Class instances (or objects) can be stack dynamic or heap dynamic
o Stack-dynamic instances are referenced directly with variables
o Heap-dynamic instances are referenced through pointers
o A stack-dynamic instance may have heap-dynamic data members
Information Hiding
o A class can have both hidden and visible entities
o Private for hidden entities
o Public for interface entities
o Protected for inheritance
Constructors:
o Functions to initialize the data members of instances
o May also allocate storage if part of the object is heap-dynamic
o Can include parameters to provide parameterization of the objects
o Implicitly called when an instance is created
o Can be explicitly called
o Can be more than one constructor
o Name is the same as the class name
Destructors
o Functions to cleanup after an instance is destroyed; usually just to reclaim
heap storage
o Implicitly called when the object’s lifetime ends
o Can be explicitly called
o Name is the class name, preceded by a tilde (~)
o All heap-dynamic objects must be explicitly deallocated by delete
C++ Example
#include <iostream.h>
class stack
{
private:
int *stackPtr;
int maxLen;
int topPtr;
public:
stack()
{
stackPtr = new int [100];
maxLen 99;
topPtr = -1;
} // stack
~stack()
{
delete [] stackPtr;
}
void push (int number)
{
if (topPtr == maxLen)
cerr << “error in push – stack is full\n”;
else stackPtr[++topPtr] = number;
}
void pop()
{
if (topPtr = = -1)
cerr << “error in pop – stack is empty\n”;
else topPtr--;
}
int top()
{
return (stackPtr[topPtr]);
}
int empty()
{
return (topPtr == -1);
}
} // stack
void main()
{
int topOne;
stack stk;
stk.push(42);
stk.push(17);
topOne = stk.top();
stk.pop();
…
}
Designing an Abstract Type
Designing an abstract type involves choosing good operations and determining how they should
behave. A few rules of thumb
o It’s better to have a few, simple operations that can be combined in powerful ways than lots
of complex operations.
o Each operation should have a well-defined purpose, and should have a coherent behavior
rather than a panoply of special cases.
o The set of operations should be adequate; there must be enough to do the kinds of
computations clients are likely to want to do. A good test is to check that every property of
an object of the type can be extracted. For example, if there were no get operation, we would
not be able to find out what the elements of the list are. Basic information should not be
inordinately difficult to obtain. The size method is not strictly necessary, because we could
apply get on increasing indices, but this is inefficient and inconvenient.
o The type may be generic: a list or a set, or a graph, for example. Or it may be domain-
specific: a street map, an employee database, a phone book, etc. But it should not mix generic
and domain-specific features.
Choice of Representations
So far, we have focused on the characterization of abstract types by their operations. In the code a
class that implements an abstract type provides a representation: the actual data structure that
supports the operations.
The implementation of an ADT provides a representation of the type and implementations of the
functions. It is written in the programming language that you are using, such as C/C++.
Linked lists are a common representation of lists, for example. The following object model shows
a linked list implementation similar (but not identical to) the Linked List class in the standard
library.
header
next prev
element
The list object has a field header that references an Entry object. An Entry object is arecord with
three fields: next and prev which may hold references to other Entry objects(or be null), and element,
which holds a reference to an element object. The next and prevfields are links that point forwards
and backwards along the list. In the middle of the list,following next and then prev will bring you
back to the object you started with. Let’s assume that the linked list does not store null references as
elements. There is always a dummy Entry at the beginning of the list whose element field is null, but
this is not interpreted as an element.
Summary
List
Entry
Object
The implementation of an ADT provides a representation of the type and implementations of
the functions. It is written in the programming language that you are using, such as C/C++.
ADTs allows the creation of instances with well-defined properties and behaviour
In object-orientation ADTs are referred to as classes. Therefore a class defines properties of
objects which are the instances in an object-oriented environment.
Questions
1. State the concept of abstract data type along with its types
Lesson 7
GROUP DISCUSSION ON
Basic concept of OOPS
Classe s and objects
Features of C++
UNIT I
LESSON 8
CONSTRUCTOR
Objectives
Concept of constructor
Parameterized constructor
Multiple constructors in a class
We will now discuss about ‘special member functions’ of a ‘class’ called ‘Constructors’
Constructors
Each time when you write a program you create a function, which is responsible for initializing the
variable, and before the end of the program you call a function to destroy the allocated variables. To
automate this feature C++ provides a concept of constructors and destructors.
C++ provides a constructor is a 'special' member function whose task is to initialize the objects of its
class. It is special because its name is the same as the class name. The constructor is invoked
whenever an object of its associated class is created. It is called constructor because it constructs the
values of data members of the class.
A constructor is declared and defined as follows:
/ / class with a constructor
class integer
{
int m, n;
public:
integer(void); / / constructor declared
……….
……….
} ;
integer:: integer(void) / / constructor defined
{
m = 0; n = 0;
}
When a class contains a constructor like the one defined above, it is guaranteed that an object created
by the class will be initialized automatically. For example, the declaration
integer int1 ; / / object int1 created
not only creates the object int1 of type integer but also initializes its data members m and n to zero.
There is no need to write an Y, statement to invoke the constructor function (as we do with the
normal member functions): If a 'normal' member function is defined for zero initialization, we would
need to invoke this function for each of the objects separately. This would be very inconvenient, if
there are a large number of objects.
A constructor that accepts no parameters is called the default constructor. The default constructor for
class A is A::AO. If no such constructor is defined, then the compiler supplies a default constructor.
Therefore a statement such as
A a;
invokes the default constructor of the compiler to create the object a.
Special characteristics of constructor functions :
They should be declared in the public section.
They are invoked automatically when the objects are created.
They do not have return types, not even void and therefore, and they cannot return values.
They cannot be inherited, though a derived class can call the base class constructor. . Like
other C++ functions, they can have default arguments.
Constructors cannot be virtual. (Meaning of virtual will be discussed later in Chapter 9.)
We cannot refer to their addresses.
An object with a constructor (or destructor) cannot be used as a member of a union. . They
make 'implicit calls' to the operators new and delete when memory allocation is required.
Remember, when a constructor is declared for a class, initialization of the class objects becomes
mandatory.
Parameterized Constructors
Constructor integer(), which we defined above, initializes the data members of all the objects to
zero. However, in practice it may be necessary to initialize the various data elements of different
objects with different values when they are created. C++ permits us to achieve this objective by
passing arguments to the constructor function when the objects are created. The constructors that can
take arguments are called parameterized constructors.
Constructor integer() may be modified to take arguments as shown below:
class integer {
int m, n;
public:
integer(int x, int y); / / parameterized constructor
};
integer :: integer(int x, int y)
{
m = x; n = y ;
}
When a constructor has been parameterized, the object declaration statement such as
integer intl ;
may not work. We must pass the initial values as arguments to the constructor function when an
object is declared. This can be done in two ways:
By calling the constructor explicitly.
By calling the constructor implicitly.
The following declaration illustrates the first method:
integer intl = integer(0,l00); / / explicit call
This statement creates an integer object int1 and passes the values 0 and 100 to it. The second is
implemented as follows:
integer intl(0,l00); / / implicit call
This method, sometimes called the shorthand method, is used very often as it is shorter, looks better
and is easy to implement.
Remember, when the constructor is parameterized, we must provide appropriate arguments for the
constructor. Program demonstrates the passing of arguments to the constructor functions.
Ex. Of parameterized constructor
# include<iostream>
using namespace std;
class integer
{
int m, n;
public:
integer(int, int); // constructor declared
void display(void)
{
cout «”m=” « m<<"\n";
cout «”n=" «n «”\n";
}
};
integer :: integer(int x. int y) // constructor defined
{
m = x;
n= y;
}
int main()
{
integer int1(O.l00); // constructor called implicitly
integer int2 = integer(25,75); // constructor called explicitly
cout « “ \nOBJECTl " «"\n";
int1.dtsplay();
cout « "\nOBJECT2" « '"\n";
int2.display();
return 0;
}
Program output:
OBJECT l
m =0
n = 100
OBJ ECT2
m = 25
n = 75
The constructor functions can also be defined as inline functions. Example:
class integer
{
int m, n;
public:
integer(int x, int y) // Inline constructor
{
m = x; Y = n;
}
………….
………….
};
The parameters of a constructor can be of any type except that of the class to which it belongs. For
example,
class A
public:
A(A);
} ;
is illegal.
However, a constructor can accept a reference to its own class as a parameter. Thus, the statement
Class A {
public:
A(A&);
} ;
is valid. In such cases, the constructor is called the copy constructor.
MULTIPLE CONSTRUCTORS IN A CLASS
So far we have used two kinds of constructors. They are:
integer () ; // No arguments
jnteger(int, int); // Two arguments
In tbe first case, the constructor itself supplies the data values and no values are passed by
the calling program. In the second case, the function call passes the appropriate values fromMain().
C++ permits us to use both these constructors in the same class. For example, wecould define a
class as follows:
class integer
{
int m, n;
public :
integer() // constructor 1
{
m=0; n=0;
}
integer(int a, int b) // constructor 2
{
m=a;n=b;
}
integer (integer & i) // constructor 3
{
m = i.m;
n = i.n;
}
This declares three constructors for an integer object. The first constructor receives no Inguments,
the second receives two integer arguments and the third receives one integer ~Ject as an argument.
For example, the declaration
integer I1;
would automatically invoke the first constructor and set both m and n of I1 to zero. The statement
integer I2(20,40);
would call the second constructor which will initialize the data members m and n of I2 to 20 and 40
respectively. Finally, the statement
integer I3(12);
would invoke the third constructor which copies the values of I2 into I3. In other words, it sets the
value of every data element of I3 to the value of the corresponding data element of I2.
As mentioned earlier, such a constructor is called the copy constructor. We learned in Chapter 4 that
the process of sharing the same name by two or more functions is referred to as function
overloading. Similarly, when more than one constructor function is defined in aclass, we say that the
constructor is overloaded.
I
#include<iostream>
using namespace std;
class complex
{
float x ,y;
public :
complex() // constructor no arg
{
}
complex(float a) // constructor – one argument
{ x = y = a;
}
complex( float real, float imag) // constructor – two arg
{
x = real;
y = imag;
}
friend complex sum(complex ,complex);
friend void show(complex);
};
complex sum(complex c1,complex c2) // friend
{
complex c3;
c3.x=c1.x+c2.x;
c3.y=c1.y+c2.y;
return(c3);
}
void show(complex c) // friend
{
cout <<c.x<<”+j”<<c.y<<”\n”;
}
int main()
{
complex A(2.7,3.5); //define & initialize
complex B(1.6); //define and initialize
complex C; //define
C=sum(A,B);
Cout << “A=”; show(A); //sum() is a friend
Cout << “B=”; show(B); //sum() is a friend
cout << “C=”; show(C); //sum() is a friend
//another way to give initial values (second method)
complex P,Q,R; // define P, Q ,R
p= complex(2.5,3.9); // initialize P
Q= complex(1.6,2.5); // initialize Q
R= sum(P,Q);
Cout <<”\n”;
Cout <<”P = “; show(P);
Cout <<”Q = “; show(Q);
Cout <<”R = “; show(R);
Return 0;
}
output will be
A=2.7+J3.5
B=1.6+J1.6
C=4.3+J5.1
P=2.5+J3.9
Q=1.6+J2.5
R=4.1+J6.4
There are three constructors in the class complex. The first constructor, which takes no arguments, is
used to create objects which are not initialized; the second, which takes one argument, is used to
create objects and initialize them; and the third, which takes two arguments, is also used to create
objects and initialize them to specific values. Note that the second method
Summary
C++ provides a constructor is a 'special' member function whose task is to initialize the
objects of its class. It is special because its name is the same as the class name.
The constructor is invoked whenever an object of its associated class is created. It is call
constructor because it constructs the values of data members of the class.
A constructor that accepts no parameters is called the default constructor. The default
constructor for class A is A::AO.
Questions
1 . Deifne constructor concept along with example
2 What is parameterised constructor ? explain with example.
UNIT I
Lesson 9
CONSTRUCTOR II
Objectives
Constructor with default arguments
Copy constructor
Destructor
CONSTRUCTORS WITH DEFAULT ARGUMENTS
It is possible to define constructors with default arguments. For example, the constructor complexO
can be declared as follows:
complex(float real, float imag=0);
The default value of the argument imag is zero. Then, the statement
complex C(5.0);
I
assigns the value 5.0 to the real variable and 0.0 to imag (by default). However, the statement
complex C(2.0,3.0);
assigns 2.0 to real and 3.0 to imag. The actual parameter, when specified, Overrides the default
value. As pointed out earlier, the missing arguments must be the trailing ones. .
COPY CONSTRUCTOR
A copy constructor is used to declare and initialize an object from another
object. For example, the statement
integer 12(11);
would define the object 12 and at the same time initialize it to the values of Il. Another form of this
statement is
integer I2 = 11;
The process of initializing through a copy constructor is known as copy initialization. Remember,
the statement
I2 = 11;
will not invoke the copy constructor. However, if Il and I2 are objects, this statement is legal and
simply assigns the values of I1 to I2, member-by-member. This is the task of the overloaded
assignment operator(=). We shall see more about this later.
A copy constructor takes a reference to an object of the same class as itself as an argument. Let us
consider a simple example of constructing and using a copy constructor
# include<iostream>
using namespace std;
class code
{
int id;
public:
code() // constructor
{
}
code(int a) // constructor
{
id = a;
}
code( code & x) // copy constructor
{
id=x.id; // copy in the value
}
void display (void)
{
cout <<id;
}
};
int main()
{
code A(100); // object A is created and initialized
code B(A); // copy constructor called
code C=A; // copy constructor called again
code D; // D is created not initialized
D=A; // copy constructor not called
Cout <<”\n id of A:”; A.display();
Cout <<”\n id of B:”; B.display();
Cout <<”\n id of C:”; C.display();
Cout <<”\n id of D:”; D.display();
Return 0;
}
DESTRUCTORS
A destructor, as the name implies, is used to destroy the objects that have been created by a
constructor. Like a constructor, the destructor is a member function whose name is the same as the
class name but is preceded by a tilde. For example, the destructor for the class integer
can be defined as shown below:
~integer( )
{
}
A destructor never takes any argument nor does it return any value. It will be invoked implicitly by
the compiler upon exit from the program (or block or function as the case may be) to clean up
storage that is no longer accessible. It is a good practice to declare destructors in a program since it
releases memory space for future use.
Whenever new is used to allocate memory in the constructors, we should use delete to
free that memory. For example, the destructor for the matrix class discussed above may be
defined as follows:
matrix :: ~matrix()
{
for (int I=0;I<d1;I++)
delete p[I];
delete p;
}
This is required because when the pointers to objects go out of scope, a destructor is not called
implicitly.
The example below illustrates that the destructor has been invoked implicitly by the compiler.
Implementation of destructor
#include <iostream>
using namespace std;
int count = 0;
class alpha
{
public:
{ \
cout++;
cout « "\nNo.of object created" « count .
-alpha()
{
cout « "\nNo,of object destroyed" « count;
cout--;
}
};
int main()
{
alpha A1, A2, A3, A4;
{
cout « "\n\nENTERBLOCK1\n".
alpha A5;
}
{
cout « "\n\nENTER BLOCK2\n";
alpha A6;
}
cout « "\n\nRE-ENTER MAIN\n";
return 0;
}
output of the program is
ENTER MA I N
No.of object created 1
No.of object created 2
No.of object created 3
No.of object created 4
ENTER BLOCKl
No.of object created 5
No.of object destroyed 5
ENTER BLOCK2
No.of object created 5
No.of object destroyed 5
RE-ENTER MAIN
No.of object destroyed 4
No.of object destroyed 3
No of object destroyed 2
No.of object destroyed 1
As the objects are created and destroyed. they increase and decrease the count. Notice that after the
first group of objects is created, A5 is created, and then destroyed, A6 is created, and then destroyed.
Finally, the rest of the objects are also destroyed. When the closing brace of a scope is encountered,
the destructors for each object in the scope are called. Note that the objects are destroyed in the
reverse order of creation.
Summary
It is possible to define constructors with default arguments. For example, the constructor complexO
can be declared as follows:
complex(float real, float imag=0);
A copy constructor is used to declare and initialize an object from another object.
A destructor, as the name implies, is used to destroy the objects that
have been created by a constructor.
Questions
what is Destructor? Why it is necessary to define destructor in a program
explain copy constructor with suitable example?
UNIT I
Lesson 10
OVERLOADING
Objective
Constructor Overloading
Operator Overloading
Overloading Unary Operators
Overloading Binary Operators“By now you all must have got a fair idea of how a function and its subsequent components viz.,
arguments/parameters play an important part when used in a C++ program. We also discussed about
function returning value by referring ‘directly to the variable’ called as ‘By Val’ and returning value
by referring ‘through the address of the variable’ called as ‘By Ref’. The topic, which we are
covering, now, is an important and unique feature of object-oriented programming. Lets explore it
now….”
OVERLOADED CONSTRUCTORS IN A CLASS
when more than one constructor function is defined in a class, we say that the constructor is
overloaded. Overloaded constructor are also known as multiple constructor in a class
we have used two kinds of constructors. They are:
integer () ; // No arguments
jnteger(int, int); // Two arguments
In the first case, the constructor itself supplies the data values and no values are passed by
The calling program. In the second case, the function call passes the appropriate values from Main().
C++ permits us to use both these constructors in the same class. For example, we
could define a class as follows:
class integer
{
int m, n;
public :
integer() // constructor 1
{
m=0; n=0;
}
integer(int a, int b) // constructor 2
{
m=a;n=b;
}
integer (integer & i) // constructor 3
{
m = i.m;
n = i.n;
}
This declares three constructors for an integer object. The first constructor receives no arguments,
the second receives two integer arguments and the third receives one integer object as an argument.
For example, the declaration
integer I1;
would automatically invoke the first constructor and set both m and n of I1 to zero. The statement
integer I2(20,40);
would call the second constructor which will initialize the data members m and n of I2 to 20 and 40
respectively. Finally, the statement
integer I3(12);
would invoke the third constructor which copies the values of I2 into I3. In other words, it sets the
value of every data element of I3 to the value of the corresponding data element of I2. As mentioned
earlier, such a constructor is called the copy constructor. We learned that that the process of sharing
the same name by two or more functions is referred to as function overloading. Similarly, when
more than one constructor function is defined in a class, we say that the constructor is overloaded.
#include<iostream>
class complex
{
float x ,y;
public :
complex() // constructor no arg
{
}
complex(float a) // constructor – one argument
{
x = y = a;
}
complex( float real, float imag) // constructor – two arg
{
x=real;
y=imag;
}
friend complex sum(complex ,complex);
friend void show(complex);
};
complex sum(complex c1,complex c2) // friend
{
complex c3;
c3.x=c1.x+c2.x;
c3.y=c1.y+c2.y;
return(c3);
}
void show(complex c) // friend
{
cout <<c.x<<”+j”<<c.y<<”\n”;
}
int main()
{
complex A(2.7,3.5); //define & initialize
complex B(1.6); //define and initialize
complex C; //define
C=sum(A,B);
Cout << “A=”; show(A); //sum() is a friend
Cout << “B=”; show(B); //sum() is a friend
cout << “C=”; show(C); //sum() is a friend
//another way to give initial values (second method)
complex P,Q,R; // define P, Q ,R
p= complex(2.5,3.9); // initialize P
Q= complex(1.6,2.5); // initialize Q
R= sum(P,Q);
Cout <<”\n”;
Cout <<”P = “; show(P);
Cout <<”Q = “; show(Q);
Cout <<”R = “; show(R);
Return 0;
}
output will be
A=2.7+J3.5
B=1.6+J1.6
C=4.3+J5.1
P=2.5+J3.9
Q=1.6+J2.5
R=4.1+J6.4
There are three constructors in the class complex. The first constructor, which takes no arguments, is
used to create objects which are not initialized; the second, which takes one argument, is used to
create objects and initialize them; and the third, which takes two arguments, is also used to create
objects and initialize them to specific values.
Operator Overloading
Operator overloading is one of the many exciting features of C++ language. It is an
importanttechnique that has enhanced the power of extensibility of C++. We have stated more once
that C++ tries to make the user-defined data types behave in much the same way as built-in types.
For instance, C++ permits us to add two variables of user-defined types!
the same syntax that is applied to the basic types. This means that C++ has the ability to provide the
operators with a special meaning for a data type. The mechanism of giving such special Meanings to
an operator is known as operator overloading.
Operator overloading provides a flexible option for the creation of new definitions for of the
C++ operators. We can almost create a new language of our own by the creative use the function and
operator overloading techniques. We can overload (give additional meaning to) all the C++
operators except the following:
Class member access operators (., . *).
Scope resolution operator (::).
Size operator (sizeof).
Conditional operator (?:).
The excluded operators are very few when compared to the large number of operators, which qualify
for the operator overloading definition.
Although the semantics of an operator can be extended, we cannot change its syntax, the
grammatical rules that govern its use such as the number of operands, precedence and associativity.
For example, the multiplication operator will enjoy higher precedence than the addition operator.
Remember, when an operator is overloaded, its original meaning is not lost.
For instance, the operator +, which has been overloaded to add two vectors, can still be used to aid
two integers.
DEFINING OPERATOR OVERLOADING
To define additional task to an operator, we must specify what it means in relation to the class to
which the operator is applied. This is done with the help of a special function, called Operator
function, which describes the task. The general form of an operator function is:
return type classname :: operator (op-arg1ist)
{
Function body II task defined
}
where return type is the type of value returned by the specified operation and op is the operator
being overloaded. The op is preceded by the keyword operator. operator op is the function name.
Operator functions must be either member functions (non-static) or friend functions. A basic
difference between them is that a friend function will have only one argument for unary operators
and two for binary operators, while a member function has no arguments for unary operators and
only one for binary operators. This is because the object used to invoke the member function is
passed implicitly and therefore is available for the member function. This is not the case with friend
functions. Arguments may be passed either by value or by reference. Operator functions are declared
in the class using prototypes as follows:
vector operator+(vector); I I vector addition
vector operator-(); I I unary minus
friend vector operator+(vector, vector) ; I I vector addition
friend vector operator-(vector); I I unary minus
vector operator-(vector &a); I I subtraction
int operator= =(vector); II comparison
friend int operator.== (vector , vector) I I comparison
vector is a data type of class and may represent both magnitude and direction (as in ph' and
engineering) or a series of points called elements (as in mathematics).
The process of overloading involves the following steps:
a. Create a class that defines the data type that is to be used in the overloading operation
b. Declare the operator function operator op() in the public part of the class. It may be either a
member function or a friend function.
c. Define the operator function to implement the required operations
Overloaded operator functions can be invoked by expressions such as
op x or x op
for unary operators and
x op Y
for binary operators. op x (or x op) would be interpreted as
operator op (x)
for friend functions. Similarly, the expression x op y would be interpreted as either
x.operator op (y)
in case of member , or
operator op (x, y)
in case of friend functions. When both the forms are declared, standard argument matching is
applied to resolve any ambiguity.
OVERLOADING UNARY OPERATORS
Let us consider the unary minus operator. A minus operator when used as a unary, takes just one
operand. We know that this operator changes the sign of an operand when applied to a basic data
item. We will see here how to overload this operator so that it can be applied to an object in much
the same way as is applied to an int or float variable. The unary minus when applied to an object
should change the sign of each of its data items.
Program shows how the unary minus operator is overloaded.
OVERLOADING UNIARY MINUS
# incl,ude <iostream>
using namespace std;
class space
{
int x;
int y;
int z;
public:
void getdata(int a, int b, int c);
void display(void);
void operator -(); //overload unary minus
};
void space::getdata(int a, int b, int c)
{
x = a;
y = b;
z = c;
}
void space :: display(void)
{
cout<< x<< “ “;
cout<< y <<” “ ;
cout<<z <<”\n “;
}
void space::operator-()
{
x = -x;
y = -y;
z = -z;
}
int main()
{
space S;
S.getdata(10, -20, 30);
Cout<< “S : “;
S.display();
-S; //activates operator-() function
cout<< “S :”;
S.display();
return 0;
}
The Program produces the following output:
S : 10 -20 30
S : -10 20 –30
Remember:
The function operator- ( ) takes no argument. Then, what does this operator function do? It
changes the sign of data members of the object S. Since this function is a member function of the
same class, it can directly access the members of the object which activated it.
Remember, a statement like
S2 = -S1;
will not work because, the function operator-() does not return any value. It can work if the function
is modified to return an object.
It is possible to overload a unary minus operator using a friend function as follows:
friend void operator-(space &s); //dec1a ration
void operator- (space &s) // definition
{
s . x = -s. x ;
s . y = -s. y ;
s . z = -s. z;
}
Note that the argument is passed by reference. It Will not work if we pass argument by value
because only a copy of the object that activated the call is passed to operator-(). Therefore, the
changes made inside the operator function will not reflect in the called object.
OVERLOADING BINARY OPERATORS
We have just seen how to overload a unary operator. The same mechanism can be used to overload a
binary operator. Here, we illustrated, how to add two complex numbers using a friend function. A
statement like
C = sum(A, B); // functional notation.
was used. The functional notation can be replaced by a natural looking expression
C = A + B; // arithmetic notation
by overloading the + operator using an operator+()function. The Program illustrates how
this is accomplished.
Overloading + operator
include <iostream>
using namespace std;
class complex
{
float x; / / real part
float y; 1/ imaginary part
publ ic:
complex() { } / / constructor 1
complex(float real ,float imag) { x = real; y =imag; } / / constructor 2
complex operator+(complex);
void display(void);
}
complex complex:: operator+(complex c)
{
complex temp; //temporary
temp. x = x + c.x; //these are
temp.y = y + c.y; //float additions
return (temp);
}
void complex :: display(void)
{
cout << x <<"+ j << y <<"\n ";
}
int main()
{
complex Cl, C2, C3; // invokes constructor 1
Cl = complex(2.5, 3.5); // invokes constructor 2
C2 =complex(1.6, 2.7);
C3 = Cl + C2;
cout << "Cl = "; Cl.display();
cout << "C2 = "; C2.display();
cout << "C3 = “; C3.display();
return 0;
}
The output of Program would be:
C1 = 2.5 + j3.5
C2 = 1. 6 + j 2.7
C3 = 4.1 + j 6.2
Let us have a close look at the function operator+( ) and see how the operator overloading is
implemented.
complex complex :: operator+(complex c)
{
complex temp;
temp.x = x + c.x;
temp.y = y + c.y;
return(temp);
}
We should note the following features of this function:
1. It receives only one complex type argument explicitly.
2. It returns a complex type value.
3. It is a member function of complex.
The function is expected to add two complex values and return a complex value as I result but
receives only one value as argument. Where does the other value come from?.
Now let us look at the statement that invokes this function:
C3 = C1 + C2; / / invokes operator+() function
We know that a member function can be invoked only by an object of the same class. Here the
object Cl takes the responsibility of invoking the function and C2 plays the role of: argument that is
passed to the function. The above invocation statement is equivalent to
C3 = C1.operator+(C2); / / usual function call syntax
Therefore, in the operator+() function, the data members of Cl are accessed directly the data
members of C2 (that is passed as an argument) are accessed using the dot operator
Thus, both the objects are available for the function. For example, in the statement
temp.x = x + c.x;
c.x refers to the object C2 and x refers to the object Cl.temp.x is the real part of temp has been
created specially to hold the results of addition of C land C2. The function return the complex temp
to be assigned to C3.
As a rule, in overloading of binary operators, the left-hand operand is used to invoke operator
function and the right- hand operand is passed as an argument.
Summary
when more than one constructor function is defined in a class, we say that the constructor is
overloaded.
The process of overloading involves the following steps:
a. Create a class that defines the data type that is to be used in the overloading operation
b. Declare the operator function operator op() in the public part of the class. It may be either a
member function or a friend function.
c. Define the operator function to implement the required operations
Questions
Explain concept of Constructor Overloading
Explain concept of Operator Overloading
Explain concept of Unary and Binary Operator Overloading
UNIT I
LESSON 11
OVERLOADING II
Objective
Concept of function overloading
In the previous lecture of ovrloading we have got concept of constructor and operator oveloading.
Here in this second part we will discuss most powerful application of OOP viz. Function
Oveloading, by which we can do variety of tasks . Let’s go through it.
FUNCTION OVERLOADING
Overloading refers to the use of the same thing for different purposes. C++ also permits overloading
of functions. This means that we can use the same function name to create functions that perform a
variety of different tasks. This is known as function polymorphism in OOP. The ability to have
various functions with the same name in the same program is called function overloading. The most
important rule about function overloading is to make sure that each one of these functions has a
different number or different type(s) of arguments.
Using the concept of function overloading; we can design a family of functions with one function
name but with different argument lists. The function would perform different, operations depending
on the argument list in the function call. The correct function to invoked is determined by checking
the number and type of the arguments but not on the function type. For example, an overloaded
add() function handles different types of data shown below:
/ / Declarations
int add(int a, int b); / / prototype 1
int add(int a, intb, int c); / / prototype 2
double add (double x, double y); / / prototype 3
double add(int p, double q); / / prototype 4
double add(double p, int q); / / prototype 5
/ / Function calls
cout « add(5, 10); / / uses prototype 1
cout « add(15, 10.0); / / uses prototype 2
cout « add(12.5, 7.5); / / uses prototype 3
cout « add(5, 10. 15); / / uses prototype 4
cout « add(0.75, 5); / / uses prototype 5
A function call first matches the prototype having the same number and type of argument and then
calls the appropriate function for execution. A best match must be unique. The function
Selection involves following steps
1. The complier first tries to find an exact match in which the types of actual argument
are the same, and use that function.
2. If an exact match is not found, the compiler uses the integral promotions to the actual
argument, such as,
char to int
Float t to double
d. When either of them fails, the compiler tries to use the built-in conversions(the implicit
assignment. conversion) to the actual arguments and then uses function whose match is unique.
If the conversion is possible to have multimatches, then the compiler will generate an error
message.
e. Suppose we use following two functions:
long square(long n)
double square (double x)
A function call such as
square(10)
will cause an error because int argument can be converted to either long or double, thereby
creating an ambiguous situation as to which version of square() should be used.
4. If all of the steps fail, then the compiler will try the user-defined conversions in combination
with integral promotions and built-in conversions to find a unique match. User-defined
conversions are often used in handling class objects.
Program illustrates function overloading.
// Function volume() is overloaded three times I
#include <iostream>
using namespace std;
// Declaration (prototypes)
int volume(int);
double volume( double, int) ;
long volume (long, int , int);
int main()
(
cout « volume(10) « "\n";
cout « volume(2.5,8) « "\n";
cout « volume(100L,75,15) « "\n";
return 0;
}
/ / Function definitions
int volume(int s) // cube
(
return(s*s*s);
}
double volume(double r. int h) //cylinder
{
return (3 .14519,*r*r*h) ;
}
1ong volume (long l, int b, int h) //rectangular box
{
return (l*b*h);
}
The output of program:
1000
157.26
112500
Overloading of function should be done with caution. We should not overload unrelated functions
and should reserve function overloading for function that performs closely related tasks. Sometime,
the default arguments may be used instead of overloading. This may reduce the number of functions
to be defined.
Summary
The ability to have various functions with the same name in the same program is called
function overloading. The most important rule about function overloading is to make sure
that each one of these functions has a different number or different type(s) of arguments.
Overloading of function should be done with caution. We should not overload unrelated
functions and should reserve function overloading for function that performs closely related
tasks.
Questions
Explain the concept of Function Overloading with example
UNIT I
LESSON 12
ARRAYS
Objectives.
Concept of Arrays
Multidimensional Arrays
Strings of Characters
Arrays are a series of elements (variables) of the same type placed consecutively in memory that can
be individually referenced by adding an index to a unique name.
For example, an array to contain 5 integer values of type int called billy could be represented this
way:
where each blank panel represents an element of the array, that in this case are integer values of type
int. These are numbered from 0 to 4 since in arrays the first index is always 0, independently of its
length .
Like any other variable, an array must be declared before it is used. A typical declaration for an array
in C++ is:
type name [elements];
where type is a valid object type (int, float...), name is a valid variable identifier and the elements
field, that is enclosed within brackets [], specifies how many of these elements the array contains.
Therefore, to declare billy as shown above it is as simple as the following sentence:
int billy [5];
NOTE: The elements field within brackets [] when declaring an array must be a constant
value, since arrays are blocks of static memory of a given size and the compiler must be able
to determine exactly how much memory it must assign to the array before any instruction is
considered.
Initializing arrays.
When declaring an array of local scope (within a function), if we do not specify otherwise, it will not
be initialized, so its content is undetermined until we store some values in it.
If we declare a global array (outside any function) its content will be initialized with all its elements
filled with zeros. Thus, if in the global scope we declare:
int billy [5];
every element of billy will be set initialy to 0:
But additionally, when we declare an Array, we have the possibility to assign initial values to each
one of its elements using curly brackets { }. For example:
int billy [5] = { 16, 2, 77, 40, 12071 };
this declaration would have created an array like the following one:
The number of elements in the array that we initialized within curly brackets { } must match the
length in elements that we declared for the array enclosed within square brackets [ ]. For example,
in the example of the billy array we have declared that it had 5 elements and in the list of initial
values within curly brackets { } we have set 5 different values, one for each element.
Because this can be considered useless repetition, C++ includes the possibility of leaving the
brackets empty [ ] and the size of the Array will be defined by the number of values included
between curly brackets { }:
int billy [] = { 16, 2, 77, 40, 12071 };
Access to the values of an Array.
In any point of the program in which the array is visible we can access individually anyone of its
values for reading or modifying as if it was a normal variable. The format is the following:
name[index]
Following the previous examples in which billy had 5 elements and each of those elements was of
type int, the name which we can use to refer to each element is the following:
For example, to store the value 75 in the third element of billy a suitable sentence would be:
billy[2] = 75;
and, for example, to pass the value of the third element of billy to the variable a, we could write:
a = billy[2];
Therefore, for all purposes, the expression billy[2] is like any other variable of type int.
Notice that the third element of billy is specified billy[2], since first is billy[0], the second is
billy[1], and therefore, third is billy[2]. By this same reason, its last element is billy[4]. Since
if we wrote billy[5], we would be acceding to the sixth element of billy and therefore exceeding
the size of the array.
In C++ it is perfectly valid to exceed the valid range of indices for an Array, which can create
problems since they do not cause compilation errors but they can cause unexpected results or serious
errors during execution. The reason why this is allowed will be seen farther ahead when we begin to
use pointers.
At this point it is important to be able to clearly distinguish between the two uses that brackets [ ]
have related to arrays. They perform two differt tasks: one is to set the size of arrays when declaring
them; and second is to specify indices for a concrete array element when referring to it. We must
simply take care not to confuse these two possible uses of brackets [ ] with arrays:
int billy[5]; // declaration of a new Array (begins with a
type name)
billy[2] = 75; // access to an element of the Array.
Other valid operations with arrays:
billy[0] = a;
billy[a] = 75;
b = billy [a+2];
billy[billy[a]] = billy[2] + 5;
// arrays example
#include <iostream.h>
int billy [] = {16, 2, 77, 40, 12071};
int n, result=0;
int main ()
{
for ( n=0 ; n<5 ; n++ )
{
result += billy[n];
}
cout << result;
return 0;
}
output
12206
Multidimensional Arrays
Multidimensional arrays can be described as arrays of arrays. For example, a bidimensional array
can be imagined as a bidimensional table of a uniform concrete data type.
jimmy represents a bidimensional array of 3 per 5 values of type int. The way to declare this array
would be:
int jimmy [3][5];
and, for example, the way to reference the second element vertically and fourth horizontally in an
expression would be:
jimmy[1][3]
(remember that array indices always begin by 0).
Multidimensional arrays are not limited to two indices (two dimensions). They can contain as many
indices as needed, although it is rare to have to represent more than 3 dimensions. Just consider the
amount of memory that an array with many indices may need. For example:
char century [100][365][24][60][60];
assigns a char for each second contained in a century, that is more than 3 billion chars! This would
consume about 3000 megabytes of RAM memory if we could declare it.
Multidimensional arrays are nothing more than an abstraction, since we can obtain the same results
with a simple array just by putting a factor between its indices:
int jimmy [3][5]; is equivalent to
int jimmy [15]; (3 * 5 = 15)
with the only difference that the compiler remembers for us the depth of each imaginary dimension.
Serve as example these two pieces of code, with exactly the same result, one using bidimensional
arrays and the other using only simple arrays:
// multidimensional array
#include <iostream.h>
#define WIDTH 5
#define HEIGHT 3
int jimmy [HEIGHT][WIDTH];
int n,m;
int main ()
{
for (n=0;n<HEIGHT;n++)
for (m=0;m<WIDTH;m++)
{
jimmy[n][m]=(n+1)*(m+1);
}
return 0;
}
program above do not produce any output on the screen, but both assign values to the memory block
called jimmy in the following way:
We have used defined constants (#define) to simplify possible future modifications of the program,
for example, in case that we decided to enlarge the array to a height of 4 instead of 3 it could be done
by changing the line:
#define HEIGHT 3
to
#define HEIGHT 4
with no need to make any other modifications to the program.
Arrays as parameters
At some moment we may need to pass an array to a function as a parameter. In C++ is not possible
to pass by value a complete block of memory as a parameter to a function, even if it is ordered as an
array, but it is allowed to pass its address. This has almost the same practical effect and it is a much
faster and more efficient operation.
In order to admit arrays as parameters the only thing that we must do when declaring the function is
to specify in the argument the base type for the array, an identifier and a pair of void brackets [].
For example, the following function:
void procedure (int arg[])
admits a parameter of type "Array of int" called arg. In order to pass to this function an array
declared as:
int myarray [40];
it would be enough to write a call like this:
procedure (myarray);
Here you have a complete example:
// arrays as parameters
#include <iostream.h>
void printarray (int arg[], int length) {
for (int n=0; n<length; n++)
cout << arg[n] << " ";
cout << "\n";
}
int main ()
{
int firstarray[] = {5, 10, 15};
int secondarray[] = {2, 4, 6, 8, 10};
printarray (firstarray,3);
printarray (secondarray,5);
return 0;
}
output
5 10 152 4 6 8 10
As you can see, the first argument (int arg[]) admits any array of type int, whatever its length is.
For that reason we have included a second parameter that tells the function the length of each array
that we pass to it as the first parameter. This allows the for loop that prints out the array to know the
range to check in the passed array.
In a function declaration is also possible to include multidimensional arrays. The format for a
tridimensional array is:
base_type[][depth][depth]
for example, a function with a multidimensional array as argument could be:
void procedure (int myarray[][3][4])
notice that the first brackets [] are void and the following ones are not. This must always be thus
because the compiler must be able to determine within the function which is the depth of each
additional dimension.
Arrays, both simple or multidimensional, passed as function parameters are a quite common source
of errors for less experienced programmers.
Strings of Characters
In all programs seen until now, we have used only numerical variables, used to express numbers
exclusively. But in addition to numerical variables there also exist strings of characters, that allow us
to represent successions of characters, like words, sentences, names, texts, et cetera. Until now we
have only used them as constants, but we have never considered variables able to contain them.
In C++ there is no specific elemental variable type to store strings of characters. In order to fulfill
this feature we can use arrays of type char, which are successions of char elements. Remember that
this data type (char) is the one used to store a single character, for that reason arrays of them are
generally used to make strings of single characters.
For example, the following array (or string of characters):
char jenny [20];
can store a string up to 20 characters long. You may imagine it thus:
This maximum size of 20 characters is not required to always be fully used. For example, jenny
could store at some moment in a program either the string of characters "Hello" or the string
"Merry christmas". Therefore, since the array of characters can store shorter strings than its total
length, a convention has been reached to end the valid content of a string with a null character,
whose constant can be written 0 or '\0'.
We could represent jenny (an array of 20 elements of type char) storing the strings of characters
"Hello" and "Merry Christmas" in the following way:
Notice how after the valid content a null character ('\0') it is included in order to indicate the end of
the string. The panels in gray color represent indeterminate values.
Initialization of strings
Because strings of characters are ordinary arrays they fulfill all their same rules. For example, if we
want to initialize a string of characters with predetermined values we can do it just like any other
array:
char mystring[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
In this case we would have declared a string of characters (array) of 6 elements of type char
initialized with the characters that compose Hello plus a null character '\0'.
Nevertheless, strings of characters have an additional way to initialize their values: using constant
strings.
In the expressions we have used in examples in previous chapters constants that represented entire
strings of characters have already appeared several times. These are specified enclosed between
double quotes ("), for example:
"the result is: "
is a constant string that we have probably used on some occasion.
Unlike single quotes (') which specify single character constants, double quotes (") are constants
that specify a succession of characters. Strings enclosed between double quotes always have a null
character ('\0') automatically appended at the end.
Therefore we could initialize the string mystring with values by either of these two ways:
char mystring [] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char mystring [] = "Hello";
In both cases the array or string of characters mystring is declared with a size of 6 characters
(elements of type char): the 5 characters that compose Hello plus a final null character ('\0')
which specifies the end of the string and that, in the second case, when using double quotes (") it is
automatically appended.
Before going further, notice that the assignation of multiple constants like double-quoted constants
(") to arrays are only valid when initializing the array, that is, at the moment when declared.
Expressions within the code like:
mystring = "Hello";
mystring[] = "Hello";
are not valid for arrays, like neither would be:
mystring = { 'H', 'e', 'l', 'l', 'o', '\0' };
So remember: We can "assign" a multiple constant to an Array only at the moment of initializing it.
The reason will be more comprehensible when you know a bit more about pointers, since then it will
be clarified that an array is simply a constant pointer pointing to an allocated block of memory. And
because of this constantnes, the array itself can not be assigned any value, but we can assing values
to each of the elements of the array.
The moment of initializing an Array it is a special case, since it is not an assignation, although the
same equal sign (=) is used. Anyway, always have the rule previously underlined present.
Assigning values to strings
Since the lvalue of an assignation can only be an element of an array and not the entire array, it
would be valid to assign a string of characters to an array of char using a method like this:
mystring[0] = 'H';mystring[1] = 'e';mystring[2] = 'l';mystring[3] = 'l';mystring[4] = 'o';mystring[5] = '\0';
But as you may think, this does not seem to be a very practical method. Generally for assigning
values to an array, and more specifically to a string of characters, a series of functions like strcpy
are used. strcpy (string copy) is defined in the cstring (string.h) library and can be called the
following way:
strcpy (string1, string2);
This does copy the content of string2 into string1. string2 can be either an array, a pointer, or a
constant string, so the following line would be a valid way to assign the constant string "Hello" to
mystring:
strcpy (mystring, "Hello");
For example:
// setting value to string
#include <iostream.h>
#include <string.h>
int main ()
{
char szMyName [20];
strcpy (szMyName,"J. Soulie");
cout << szMyName;
return 0;
}output
J. Soulie
Notice that we needed to include <string.h> header in order to be able to use function strcpy.
Although we can always write a simple function like the following setstring with the same
operation as cstring's strcpy:
// setting value to string
#include <iostream.h>
void setstring (char szOut [], char szIn [])
{
int n=0;
do {
szOut[n] = szIn[n];
} while (szIn[n++] != '\0');
}
int main ()
{
char szMyName [20];
setstring (szMyName,"J. Soulie");
cout << szMyName;
return 0;
}
output
J. Soulie
Summary
Arrays are a series of elements (variables) of the same type placed consecutively in memory
that can be individually referenced by adding an index to a unique name.
since arrays are blocks of static memory of a given size and the compiler must be able to
determine exactly how is considered.
Multidimensional arrays can be described as arrays of arrays. For example, a bidimensional
array can be imagined as a bidimensional table of a uniform concrete data type.
Questions
1. Explain Array with example
2. What is multidiamentional array concept Explain with suitable
example.
3. Find errors in each of the following
a) Assume that
Char str[5];
Cin >>str; // User types hello
b) assume that
int a[3];
cout <<a[1]<<” “ <<a[2]<< “ “a[3]<< endl;
UNIT ILesson 13
Pointers In C++
“ In the last lecture you learnt what is the concept of ‘Arrays’ Now we shift our focus to the most important topic from a programmers point of view, its about memory management. What do you percieve when we are talking about memory management? Is it related to managing storage spaces in the memory? To answer these questions, you will have to nose-dive into the memory block.”
Objective Introduction to the concept of Pointer
Introduction to Pointers
An Overview of Pointers
When writing a program, you declare the necessary variables that you will need in order to
accomplish your work. When declaring variables, you are simply asking the computer to reserve a
set amount of space in its memory for a particular object you want to use. When you declare a
variable, the computer reserves an amount of space for that variable, and uses the variable's name to
refer to that memory space. This will allow you to store something, namely the value of that
variable, in that space. Indeed, the computer refers to that space using an address. Therefore,
everything you declare has an address, just like the address of your house. You can find out what
address a particular variable is using.
Here are a few things you know already about writing a program:
To use a variable, you declare it first to tell the compiler what kind of variable you are planning to
use and what its name is . Once you declare a variable, the compiler reserves and assigns it a portion
of space in memory and locates it there so that whenever you need that variable, you just call it and
then use it.
To use a function, you have to define it, tell the compiler what the function is supposed to do, and
whether the function is supposed to give back a result or not, after it has performed its assignment.
To see a variable's address, you can use the & operator followed by the name of the variable. For
example, after declaring an integer as
int NumberOfStudents;
you can find the address where the NumberOfStudents variable is located by using:
cout << &NumberOfStudents;
This program would give you the address of the declared variable:
#include <iostream.h> int main( ){ int Value; cout << "Value lives at " << &Value; cout << "\n\n"; return 0;}After executing the program, you could get:
Value lives at:
Press any key to continueDefinition
Unfortunately, I will explain later on "WHY" use pointers. This is because we first need to know
WHAT a pointer is, HOW to declare it inside of a function, and HOW to use it. Pointers are not
particularly useful when declared and used inside of one function. They show their capabilities when
different functions (and/or objects) exchange data stored in those pointers.
As you can see from the execution of the program above, the address of a variable is very difficult to
read and interpret. Fortunately, we don't need to know that address and we don't need to know what
it means or where the variable is located. C++ provides an alternative to this problem.
Instead of referring to a variable's address directly, you are allowed to declare another variable, and
then use that new variable to refer to the address of the variable you are interested in. A pointer is a
variable that refers to another variable's address.
Just like any variable in C++, you should declare and initialize a pointer variable before using it. To
declare a pointer variable, use an identifier, followed by an asterisk (*), followed by the name of the
pointer, and a semi-colon. Here is the formula:
DateType * PointerName;
The identifier should be one of those we have learned already. This means it could be an int, a char,
a double, etc. The identifier should be the same type of identifier the pointer variable will point to.
Therefore, if you are declaring a pointer that will point to an integer variable, the pointer identifier
should be an integer.
The asterisk (*) lets the compiler know that the variable that follows is a pointer. There are three
ways you can type the asterisk. These are
DateType* PointerName;
DateType * PointerName;
DateType *PointerName;
By default, it does not matter how you append the *, the compiler will know that the thing that
follows is a variable.
Be careful when declaring various pointers. If you declare a few of them on the same line, like this:
DateType* Pointer1, Pointer2;
Only the first variable is a pointer, the second is a regular variable. If you want to declare different variables, you use:
DateType* Pointer1, *Pointer2;
Or
DateType* Pointer1;DateType* Pointer2;
Since the name of the pointer is indeed the name of a variable, you will follow the naming rules that govern every C++ variable.
#include <iostream.h>
int main( ){ int Value; int *Pointer; cout << "Value lives at " << &Value << "\n"; cout << "Pointer lives at " << &Pointer; cout << "\n\n"; return 0;}
After executing the program, you might get:
Value lives at: Pointer lives at:
Press any key to continue
Initializing a Pointer
The reason you are using a pointer is to find an alternative to knowing the address of a variable.
Therefore, from now on, we are not interested in a variable's real address. Instead, we will use a
pointer to point to that variable.
As we have learned already, a variable should be initialized before being used. This allows the
compiler to put something into the memory space allocated for that variable.
To use a pointer P effectively, for its intended purpose, you need to tell the compiler that: pointer P
will be used to point to the address of variable V. You do this by initializing the pointer. A pointer is
initialized (almost) like any other variable, using the assignment operator (=).
There are two main ways you can initialize a pointer. When declaring a pointer like this:
int* Pointer;
initialize it by following the assignment operator with & operator and the name of the variable, like
this
int* Pointer = &Variable;
You can also initialize a pointer on a different line, after declaring it. This time, you should not use
the asterisk on the Pointer, but the compiler should know that the pointer will point to a variable's
address; therefore, the name of the variable will still use the &.
#include <iostream.h>
int main( ){
int Value = 12;int *Pointer = &Value;
cout << "Value lives at: " << Value << "\n";cout << "Pointer lives at: " << *Pointer;cout << "\n\n";return 0;
}
The program would produce:
Value lives at: 12Pointer lives at: 12
Press any key to continue This program could also have the pointer initialized as:
#include <iostream.h>
int main( ){
int Value = 12;int *Pointer;
cout << "Value lives at: " << Value << "\n";
Pointer = &Value;cout << "Pointer lives at: " << *Pointer;cout << "\n\n";return 0;
}
And it would produce the same result. As another of the program, you can first declare both variables, then initialize them later on, when needed:
#include <iostream.h>
int main( ){
int Value;int *Pointer;
Pointer = &Value;Value = 26;cout << "Value = " << Value << "\n";cout << "*Pointer = " << *Pointer << "\n";
cout << "\n";return 0;
}
Once you have declare a variable and assign it to a pointer, during the course of your program, the value of a variable is likely to change, you can therefore assign it a different value:
#include <iostream.h>
int main( ){ int Value; int *Pointer; Pointer = &Value; Value = 26; cout << "Value = " << Value << "\n"; cout << "*Pointer = " << *Pointer << "\n"; Value = 35; cout << "Value = " << Value << "\n"; cout << "*Pointer = " << *Pointer << "\n"; cout << "\n"; return 0;}
As you know now, both *Pointer and Value have the same value. This allows you to change the
value of the pointer directly and affect the main variable meanwhile. Therefore, you can safely
change the value of the pointer and it will be assigned accordingly.
To see an example, make the following change to the file:
#include <iostream.h>
int main( ){
int Value;int *Pointer;
Pointer = &Value;Value = 26;cout << "Value = " << Value << "\n";cout << "*Pointer = " << *Pointer << "\n";
Value = 35;cout << "Value = " << Value << "\n";cout << "*Pointer = " << *Pointer << "\n";
*Pointer = 144;cout << "Value = " << Value << "\n";cout << "*Pointer = " << *Pointer << "\n";
cout << "\n";return 0;
}This would produce: Value = 26*Pointer = 26Value = 35*Pointer = 35Value = 144*Pointer = 144
Operations on Pointers
Consider that, added just a few rules, a pointer is a variable like any other: it can get its value from
the user (indirectly), you can apply any of the algebraic operations we have learned, it can be
incremented, it can be applied on a function, etc.
A variable is a value that is supposed to change some time to time. Since a pointer is a variable
whose value points to another variable, the value of a pointer is affected by the variable it points to.
You can use this indirection to change the value of a pointer when changing its main variable.
To get a value from the user, we have already learned that you can use the cin operator. When using
a pointer to get a value from the user, don't forget the * operator, otherwise, the compiler would get
confused.
We have already learned how to request and display the value of a regular variable from the user:
#include <iostream.h>
int main( ){
int Students;
cout << "Number of students: ";cin >> Students;
cout << "\nNumber of students: " << Students;
cout << "\n\n";return 0;
}
Once you have gotten a value and store it in a variable, it is available:
#include <iostream.h>
int main( ){
int Students;int *ptrStudents;
ptrStudents = &Students;cout << "Number of students: ";cin >> Students;cout << "\nNumber of students: " << Students << "\nThat is: " << *ptrStudents << " students.";cout << "\n\n";return 0;
}
This could produce:
Number of students: 24
Number of students: 24That is: 24 students
Press any key to continue In the same way, you can request a value from the user and store it in the pointer. To see an example, make the following change to the file:<
#include <iostream.h>
int main( ){
int Students;int *ptrStudents;
ptrStudents = &Students;cout << "Number of students: ";cin >> *ptrStudents;
cout << "\nNumber of students: " << Students << "\nThat is: " << *ptrStudents << " students.";
cout << "\n\n";return 0;
}
Of course, you can use various pointers on the same program. Apply an example by making the following changes:
#include <iostream.h>
int main( ){
int Boys;int Girls;int *ptrBoys;int *ptrGirls;
ptrBoys = &Boys;ptrGirls = &Girls;
cout << "Number of male students: ";cin >> *ptrBoys;
cout << "Number of female students: ";cin >> *ptrGirls;cout << "\nNumber of students:";
cout << "\nBoys:" << "\t" << Boys << "\nThat is: " << *ptrBoys << " students.";cout << "\nGirls:" << "\t" << Girls << "\nThat is: " << *ptrGirls << " students.";
cout << "\n\n";return 0;
}
We have learned how to perform algebraic calculations and expressions in C++. When performing
these operations on pointers, remember to use the * for each pointer involved. The calculation
should be as smooth:
#include <iostream.h>
int main( ){
int Boys;int Girls;int Total;int *ptrBoys;int *ptrGirls;int *ptrTotal;
ptrBoys = &Boys;ptrGirls = &Girls;ptrTotal = &Total;
cout << "Number of male students: ";cin >> *ptrBoys;cout << "Number of female students: ";cin >> *ptrGirls;
cout << "\nNumber of students:";cout << "\nBoys:" << "\t" << Boys << "\nThat is: " << *ptrBoys << " students.";cout << "\nGirls:" << "\t" << Girls << "\nThat is: " << *ptrGirls << " students.";
Total = Boys + Girls;
*ptrTotal = *ptrBoys + *ptrGirls;
cout << "\n\nTotal number of students: " << Total;cout << "\nThere are " << *ptrTotal << " students";
cout << "\n\n";return 0;
}
This would produce:
Number of male students: 26Number of female students: 24
Boys: 26That is: 26 studentsGirls: 24That is: 24 students
Total number of students: 50There are 50 students
Why Use Pointers?
Every time you declare a variable, the compiler puts it somewhere, which you can now refer to as an
address. Once you know that address, you can use it.
Like a reference, when you pass an argument to a function, the argument is passed using its address.
This allows the calling function to dig into the address of the variable (the argument) and use the
value directly. This transaction, like that of passing an argument by reference, allows the calling
function to alter the real value of the argument. Using this ability, a pointer can allow you to return
many values from a function; as opposed to a regular argument passing where the data, although
changed inside of the calling function, will regain its previous value once the calling function is
exited. Therefore, passing arguments as pointers allows a function to return many values, even if a
function is declared as void.
When you declare an array, you must specify the dimension of the array. That's already a problem:
what if you don't know and don't want to know the dimension of the array? Pointers provide an
ability that regular arrays do not have. Since pointers have a different and better system of managing
memory, a pointer can store an array of almost any size; this is tremendous when dealing with arrays
of characters or a whole text. Using this feature, when declaring a pointer in replacement of an array,
you do not have to worry about the size of the array, the compiler will take care of that. Again, this
feature allows you to pass pointers to a function (just like arrays) and return a value that has been
altered even if the function is declared as void. This is even more dynamic with multidimensional
arrays.
Passing Pointers to Functions
We know that a function uses arguments in order to carry its assignment. The arguments are usually
provided to the function. When necessary, a function also declares its own variable to get the desired
return value. Like other variables, pointers can be provided to a function, with just a few rules.
When declaring a function that takes a pointer as an argument, make sure you use the asterisk for the
argument or for each argument. When calling the function, use the references to the variables. The
function will perform its assignment on the referenced variable(s). After the function has performed
its assignment, the changed value(s) of the argument(s) will be preserved and given to the calling
function.
Here is a starting file from what we have learned so far:
#include <iostream.h>
int main( ){
int Shirts = 12;int Pants = 5;
cout << "Shirts = " << Shirts << endl;cout << "Pants = " << Pants << endl;
cout << endl;return 0;
}
This would produce:
Shirts = 12Pants = 5
Press any key to continue
To pass arguments to a function, you can make the following changes:
#include <iostream.h>
int main( ){
int Shirts = 3;int Pants = 5;void Deposit(int s, int p);
cout << "When starting, within main( ):\n";
cout << "\tShirts = " << Shirts << endl;cout << "\tPants = " << Pants << endl;
Deposit(Shirts, Pants);
cout << "\n\nAfter calling Deposit( ), within main( ):\n";cout << "\tShirts = " << Shirts << endl;
cout << "\tPants = " << Pants << endl;cout << endl;return 0;
}
void Deposit(int s, int p){
s = 8;p = 12;
cout << "Within Deposit( )" << "\n\tShirts = " << s << "\n\tPants = " << p;
}
After executing, the program would produce:
When starting, within main( ): Shirts = 3 Pants = 5Within Deposit( ) Shirts = 8 Pants = 12After calling Deposit( ), Within main( ): Shirts = 3 Pants = 5
Press any key to continue
To pass pointer arguments, use the asterisks when declaring the function, and use the ampersand & when calling the function. Here is an example:
#include <iostream.h>
int main( ){
int Shirts = 12;int Pants = 5;void Deposit(int s, int p);void Pickup(int *sht, int *pt);
cout << "When starting, within main( ):\n";
cout << "\tShirts = " << Shirts << endl;cout << "\tPants = " << Pants << endl;
Deposit(Shirts, Pants);cout << "\n\nAfter calling Deposit( ), within main( ):\n";cout << "\tShirts = " << Shirts << endl;cout << "\tPants = " << Pants << endl;
Pickup(&Shirts, &Pants);cout << "\n\nAfter calling Pickup( ), within main( ):\n";cout << "\tShirts = " << Shirts << endl;cout << "\tPants = " << Pants << endl;
cout << endl;return 0;
}
void Deposit(int s, int p){ s = 8; p = 5; cout << "\nWithin Deposit( )" << "\n\tShirts = " << s << "\n\tPants = " << p;}
void Pickup(int *sht, int *pt){ *sht = 26; *pt = 17; cout << "\nWithin Pickup( )" << "\n\tShirts = " << *sht << "\n\tPants = " << *pt;}
The result of executing the program is:
When starting, within main( ): Shirts = 12 Pants = 5
Within Deposit( ) Shirts = 8 Pants = 5
After calling Deposit( ), within main( ): Shirts = 12 Pants = 5
Within Pickup( ) Shirts = 26 Pants = 17
After calling Pickup( ), within main( ): Shirts = 26 Pants = 17
Summary
A pointer is a variable that refers to another variable's address.
Just like any variable in C++, you should declare and initialize a pointer variable before using it.
To declare a pointer variable, use an identifier, followed by an asterisk (*), followed by the name
of the pointer, and a semi-colon.
passing arguments as pointers allows a function to return many values, even if a function is
declared as void.
Pointers provide an ability that regular arrays do not have. Since pointers have a different and
better system of managing memory, a pointer can store an array of almost any size; this is
tremendous when dealing with arrays of characters or a whole text.
Questions
4. Explain the concept of Pointer5. Predict the output of the following program.
Class test{private:int m;public:void getdata(){cout<<”Enter number:”;cin>>m;}
void display(){cout << m;}};
main(){test T;T->getdata();T->display();Test *p;P=new test;p.getdata();(*p).display();}
UNIT I
Lesson 14
INHERITANCE
Objective
Concept of Inheritance
Types of Inheritance
“Now we take on from all the previous topics in C++ to the most inquisitive and exiting topic in C+
+ which is students favorite topics…. ‘Inheritance’.”
“What do you recollect when you talk about inheritance? Doesn’t it immediately relate to
imbibing/inheriting certain characteristics from our parents? Absolutely we are talking about
‘taking over’ certain characteristics from the ‘parent body’ to the ‘child body’. Lets explore this
phenomenon of ‘Inheritance’ in C++ now….”
INTRODUCTION
Reusability is yet another important feature of OOP. It is always nice if we could reuse something
that already exists rather than trying to create the same all over again. It, saves time and money but
also increase reliability. For instance the reuse of a class that has already been tested, debugged and
used many times can the effort of developing and testing the same again.
Fortunately, C++ strongly supports the concept of reusability. The C++ classes reused in several
ways. Once a class has been written and tested, it can be adapted by other programmers to suit their
requirements. This is basically done by creating new reusing the properties of the existing ones
The mechanism of deriving a new class from an old one is called inheritance (or derivation). The
old class is referred to as the base class and the new one is called the derived class or subclass.
The derived class inherits some or all of the traits from the base class. A class can also inherit
properties from more than one class or from more than one level. A derived class with one base
class, is called single inheritance and one with several base classes is called multiple
inheritance. On the other hand, the traits of one class may be inherited by more than one
class . This process is known as hierarchical inheritance. The mechanism of deriving from another
'derived class' is known as multilevel inheritance. Fig . shows forms of inheritance that could be
used for writing extensible programs. The direction , indicates the direction of inheritance. (Some
authors show the arrow in opposite
Authors show the arrow in opposite direction meaning "inherited from".)
b) multiple inheritance (a) single inheritance (c) Hirarchical inheritance
(d) Multilevel inheritance (e) Hybrid inheritance
fig. Forms of inheritance
A
B
D
CB
AA
B
C
A B
C
A
DCB
DEFINING DERIVED CLASSES
. Derived class can be defined by specifying its relationship with the base class in addition own
details. The general form of defining a derived class is:
c1ass der ved class-name : visibility-mode base-c1ass-name
{
…………………//
…………………// members of derived class
…………………//
};
The colon indicates that the derived-class-name is derived from the base-class-nam, visibility-mode
is optional and, if present, may be either private or public. The default visibility, mode is private.
Visibility mode specifies whether the features of the base class are privately derived or publicly
derived.
Examples:
class ABC: private XYZ // private derivation
{
members of ABC
} ;
class ABC: public XYZ // public derivation
{
members of ABC
} ;
class ABC: XYZ // private derivation by default
{
members of ABC
};
When a base class is privately inherited by a derived class, 'public members' of the class become
'private members' of the derived class and therefore the public members of base class can only be
accessed by the member functions of the derived class. They are inaccessible to the objects of the
derived class. Remember, a public member of a class can accessed by its own objects using the dot
operator. The result is that no member of the class is accessible to the objects of the derived class.
SINGLE INHERITANCE
Let us consider a simple example to illustrate inheritance. Program shows a base class B and
derived class D. The class B contains one private data member, one public data member and three
public member functions. The class D contains one private data member and two public member
functions.
#include <iostream>
using namespace std;
class B
{
int a; //private ; not inheritable
public:
int b; //public; ready for inheritance
void get_ab();
int get_a(void);
void show_a(void);
};
class D : public B // public derivation
{
int c;
public :
void mul(void);
void display(void);
};
void B :: get_ab(void)
{
a=5;b=10;
}
int b :: get_a()
{
return a;
}
void B :: show_a()
{
cout <<”a=” <<a<<”\n”;
}
void D :: mul()
{
c=b*get_a();
}
void D :: display()
{
cout <<”a=”<<get_a()<<”\n”;
cout <<”b=”<<b <<”\n”;
cout <<”c=”<<c <<”\n \n ”;
}
int main()
{
D d;
d.get_ab();
d.mul();
d.show_a();
d.display();
d.b=20;
d.mul();
d.display();
return 0;
}
Given below is the output of above Program :
a = 5
a = 5
b = 10
c = 50
a = 5
b = 20
c = 100
The class D is a public derivation of the base class B. Therefore, D inherits all the public members of
B and retains their visibility. Thus a public member of the base class B is also a public member of
the derived class D. The private members of B cannot be inherited by D.
Questions
1. Discuss overview of the Inheritance
UNIT I
LESSON 15
INHERITANCE II
Objective
Types of inheritance
MULTILEVEL INHERITANCE
It is not uncommon that a class is derived from another derived class as shown in Fig. The class A
serves as a base class for the derived class B, which in turn serves as a base class for the derived
class C. The class B is known as intermediate base class since it provides a link for the inheritance
between A and C. The chain ABC is known as inheritance path.
A derived class with multilevel inheritance is declared as follows:
class A{ }; // Base class
class B: public A { }; // B derived from A
class C: public B { }; // C derived from B
This process can be extended to any number of levels.
Base class Grandfather
Intermediate base class Father
Derived class Child
Multilevel inheritance
Let us consider a simple example. Assume that the test results of a batch of students are stored in
three different classes. Class student stores the roll-number, class test stores the marks obtained in
A
B
C
two subjects and class result contains the total marks obtained in the test. The class result can
inherit the details of the marks obtained in the test and the roll number of students through multilevel
inheritance. Example:
class student
{
protected:
int roll_number;
public:
void get number(int);
void put_number{void);
};
void student :: get_number(int a)
{
roll_number = a;
}
void student :: put_numberO
{
cout << "Roll Number: " << roll number << "\n";
}
class test : public student // First level derivation
{
protected:
float subl;
float sub2;
public:
void get_marks(float, float);
void put_marks(void);
};
void test :: get_marks(float x, float y)
{
subl = X;
sub2 = y;
}
void test :: put marks 0
{
cout << "Marks in SUBl = " << subl << "\n";
cout << "Marks in SUB2 = " << sub2 <<"\n";
}
class result : public test // Second level derivation
{
float total; // private by default
public:
void display(void);
};
The class result, after inheritance from 'grandfather' through 'father', would contain
following members:
private:
float tota1; // own member
protected:
int roll_number; // inherited from student via test
float subl; // inherited from test
float sub2; // inherited from test
public:
void get_number(int); // from student via test
void put_number(void); // from student via test
void get marks(float, float); // from test
void put-marks(void); // from test
void display(void); // own member
The inherited functions put_number() and put_marks() can be used in the definition of
display() function:
void result :: display(void)
{
total = subl + sub2;
put_number();
put_marks();
cout <<"Total = " << total << "\n";
}
Here is a simple main() program:
int main()
{
result student1; / / student1 created
studentl.get_number(111);
studentl.get_marks(75.0, 59.5);
studentl.display();
return 0;
}
This will display the result of student1. The complete program is shown below
MULTILEVEL INHERITANCE
# include <iostream>
using namespace std;
class student
{
protected:
int roll_number;
public:
void get_number(int);
void put_number(void);
};
void student :: get_number(int a)
{
roll_number = a;
}
void student :: put_number(int a)
{
cout << “Roll number: “ << roll_number << “\n”;
}
class test : public student // First level derivation
{
protected:
float sub1;
float sub2;
public:
void get_marks(float, float);
void put_marks(void);
};
void test :: get_marks(float x, float y)
{
sub1 = x;
sub2 = y;
}
void test :: put_marks()
{
cout << “Marks in SUB1 = “ << sub1 << “\n”;
cout << “Marks in SUB2 = “ << sub2 << “\n”;
}
class result : public test // Second level derivation
{
float total; // private by default
public:
void display(void);
};
void result :: display(void)
{
total = sub1 + sub2;
put_number();
put_marks();
cout << “Total = “ << total << “\n”;
}
int main()
{
result student1; // student1 created
student1.get_number(111);
student1.get_marks(75.0, 59.5);
student1.display();
return 0;
}
Program displays the following output:
Roll Number: 111
Marks in SUB1 = 75
Marks in SUB2 = 59.5
Total = 134.5
MULTIPLE INHERITANCE
A class can inherit the attributes of two or more classes as shown in Fig.This is known as multiple
inheritance. Multiple inheritance allows us to combine the features of several existing classes as a
starting point for defining new classes. It is like a child inheriting the physical features of one parent
and the intelligence of another.
Multiple inheritance
The syntax of a derived class with multiple base classes is as follows:
where, visibility may be either public or private. The base classes are separated by commas.
Example:
class P : public M, public N
{
B-2 B-nB1
D
Class D visibility B-1, visibility B-2……….{……………………(body of D)…………};
public:
void display(void);
};
Classes M and N have been specified as follows:
class M
{
protected:
int m;
public:
void get_m(int);
};
void M :: get_m(int x)
{
m = x;
}
class N
{
protected:
int n;
public:
void get_n(int);
};
void N :: get_n(int y)
{
n = y;
}
The derived class P, as declared above, would, in effect, contain all the members of M and N
in addition to its own members as shown below:
class P
{
protected:
// from M
// from M
public:
// from M
// from N
// own member
};
The member function display() can be defined as follows:
void P :: display(void)
{
cout << "m = " << m <<"\n";
cout << "n = " << n << "\n";
cout << "m*n =" << m*n << "\n";
};
The main() function which provides the user-interface may be written as follows:
main ()
{
P p;
p.get_m(l0) ;
p.get_n(20) ;
p.display () ;
}
int m;int n;
void get_m(int); void get_n(int); void display(void);
summary
A class can inherit the attributes of two or more classes .This is known as multiple
inheritance.
Multiple inheritance allows us to combine the features of several existing classes as a starting
point for defining new classes. It is like a child inheriting the physical features of one parent
and the intelligence of another.
A class can inherit the attributes of two or more classes.This is known as multiple
inheritance.
Questions
1.What is Inheritance? Explain its types in brief
2.what is multiple inheritance? Explain
UNIT I
LESSON 16
INHERITANCE III
Objective
Hierarchical Inheritance
Hybrid Inheritance
Constructors In Derived Classes
HIERARCHICAL INHERITANCE
We have discussed so far how inheritance can be used to modify a class when it did not satisfy the
requirements of a particular problem on hand. Additional members are added through inheritance to
extend the capabilities of a class. Another interesting application of inheritance is to use it as a
support to the hierarchical design of a program. Many programming problem can be cast into a
hierarchy where certain features of one level are shared by many others below that level.
As an example, following Fig. shows a hierarchical classification of students in a university
Hierarchical classification of students
Another example could be the classification of accounts in a commercial bank.
MedicalEngineeringArts
Students
Mech. Elec. Civil
Classification of bank accounts
All the students have certain things in common and, similarly, all the account possess certain
common features.
In C++, such problems can be easily converted into class hierarchies. The base class will
include all the features that are common to the subclasses. A subclass can be constructed by
inheriting the properties of the base class. A subclass can serve as a base class for the lower level
classes and so on.
HYBRID INHERITANCE
There could be situations where we need to apply two or more types of inheritance to design
a program. For instance, consider the case of processing the student results. Assume that we have to
give weightage for sports before finalising the results. The weightage for sports is stored in a
separate class called sports. The new inheritance relationship between the various classes would be
as shown.
Multilevel. multiple inheritance
Student
Test
Result
Student
Short Term Medium Term Long Term
Current AccountFixed Deposit Account
Savings Account
Account
The sports class might look like:
class sports
{
protected:
float score;
public:
void get_score(f1oat);
void put_score(void);
};
The result will have both the multilevel and multiple inheritances and its declaration would
be as follows:
class sports: public test, public sports
{
… …
… …
} ;
Where test itself is a derived class from student. That is
class test : pub1ic student
{
… …
… …
};
Program illustrates the implementation of both multilevel and multiple inheritance.
#include <iostream>
using namespace std;
class student
{
protected:
int roll_number;
public:
void get_number(int a)
{
roll_number = a;
}
void put_number(void)
{
cout << “Roll No: “ << roll_number << “\n”;
}
};
class test : public student
{
protected:
f1oat part1, part2;
public:
void get marks (float x, float y)
{
partl = x;
part2 = y;
}
void put marks(void)
{
cout << "Marks obtained: " << "\n"
<< “Part1 = “ << part1 << "\n"
<< “Part2 = “ << part2 << "\n";
}
};
class sports : public virtual student
{
protected:
float score;
public:
void get_score (float s)
{
score = s;
}
void put score(void)
{
cout << "Sports wt: " << score << "\n\n";
}
};
class result : public test, public sports
{
float tota1;
public:
void display(void);
};
void result :: display(void)
{
total = part1 + part2 + score;
put_number();
put_marks();
put_score();
cout << "Total Score: " << total << "\n”;
}
int main()
{
resu1t student _1 ;
student_l.get score(7.0);
student_1.display();
return 0;
}
CONSTRUCTORS IN DERIVED CLASSES
As we know, the constructors play an important role in initializing objects. We did not use them
earlier in the derived classes for the sake of simplicity. One important thing to note here is that, as
long as no base class constructor takes any arguments, the derived class need not have a constructor
function. However, if any base class contains a constructor with one or more arguments, then it is
mandatory for the derived class to have a constructor and pass the arguments to the base class
constructors. Remember, while applying inheritance we usually create objects using the derived
class. Thus, it makes sense for the derived class to pass arguments to the base class constructor.
When both the derived and base classes contain constructors, the base constructor is executed first
and then the constructor in the derived class is executed. .
Incase of multiple inheritance, the base classes are constructed in the order in which they
appear in the declaration of the derived class. Similarly, in a multilevel inheritance, the constructors
will be executed in the order of inheritance
Since the derived class takes the responsibility of supplying initial values to its base classes,
we supply the initial values that are required by all the classes together, when a derived class is
declared. How are they passed to the base class constructors so that they can do their job? C++
supports a special argument passing mechanism for such situations.
The constructor of the derived class receives the entire list of values as its arguments and
passes them on to the base constructors in the order in which they are declared in the derived class.
The base constructors are called and executed before executing the statements in the body of the
derived constructor.
The general form of defining a derived constructor is:
The header line of derived-constructor function contains two parts separated by a colon(;),
The first part provides the declaration of the arguments that are passed to the derived, constructor
and the second part lists the function calls to the base constructors.
basel(arglistl), base2(arglist2)... are function calls to base constructors basel(),base2(), ... and
therefore arglistl, arglist2, ... etc. represent the actual parameters that are passed to the base
constructors. Arglistl through ArglistN are the argument declarations for base constructors base1
through baseN. ArglistD provides the parameters that are necessary to initialize the members of the
derived class.
Example:
D(int a1, int a2, float bl, float b2, int d1):
A(al, a2), /* call to constructor A */
B(bl, b2) /* call to constructor B */
{
d = d1; // executes its own body
}
A(al, a2) invokes the base constructor A() and B(bl, b2) invokes another base constructor
B(). The constructor D() supplies the values for these four arguments. In addition, it has one
Derived-constructor (Arglist1, Arglist2, …… ArglistN, Arglist(D)
base1(arglist1),base1(arglist1),……………… arguments for base(N)baseN(arglistN),{Body of derived constructor}
argument of its own. The constructor D() has a total of five arguments. D() may be invoked as
follows:
……
D obj D (5, 12, 2.5, 7.54, 30);
……
These values are assigned to various parameters by the constructor D() as follows:
5 a1
12 a2
2.5 b1
7.54 b2
30 d1
The constructors for virtual base classes are invoked before any non-virtual base classes. If
Ther are multiple virtual base classes, they are invoked in the order in which they are declared. Any
non-virtua1 bases are then constructed before the derived class constructor is executed. See Table
below:
Method of inheritance Order of execution
Class B: public A
{
};
A() ; base constructor
B() ; derived constructor
Class A : public B, public C
{
};
B() : base(first)
C() : basae (second)
A() :derived
Class A : public B, virtual public C
{
};
C() : virtual base
B() : ordinary base
A() : derived
CONSTRUCTORS IN DERIVED CLASS
Program below illustrates how constructors are implemented when the classes are inherited.
#inc1ude <iostream>
using namespace std;
class alpha
{
int x;
pub1ic :
a1pha(int i)
{
x = I;
cout << "alpha initialized \n";
}
void show x(void)
{ cout << "x = " << x << "\n"; }
};
c1ass beta
{
float y;
public:
beta(float j)
{
y = j;
cout << "beta initialized \n";
}
void show_y(void)
{ cout << "y = " << y << "\n"; }
};
class gamma: public beta, public alpha
{
int m, n;
public:
gamma(int a, float b, int c, int d):
alpha(a), beta(b)
{
m = c;
n = d;
cout << “m = “ << m << “\n”
<< “n = “ << n << “\n”;
}
};
int main()
{
gamma g(5, 10.75, 20, 30):
cout << “\n”;
g.show_x();
g.show_y();
g.show_mn();
return 0;
}
The output of the program would be:
beta initialized
alpha initialized
gamma initialized
x = 5
y = 10.75
m = 20
n = 30
Summary
Application of inheritance is to use it as a support to the hierarchical design of a
program. Many programming problem can be cast into a hierarchy where certain
features of one level are shared by many others below that level.
Incase of multiple inheritance, the base classes are constructed in the order in which
they appear in the declaration of the derived class. Similarly, in a multilevel
inheritance, the constructors will be executed in the order of inheritance
Questions
1. Explain hybrid inheritance with example
2. What is hierarchical inheritance?
3. Explain Constructors In Derived Classes
4. Briefly define each of the following terminologies
i. Inheritance
ii. Multiple Inheritance
iii. Base class
iv. Derived Class
5 Distinguish between Single Inheritance and Multiple Inheritance
UNIT I
Lesson 17
Tutorial based on the concept of Constructor and Inheritance
UNIT I
LESSON 18
VIRTUAL FUNCTIONS
Objective
Concept of virtual functions
Rules of virtual functions
Pure virtual functions
The concept of polymorphism in C++ is the capability to create member functions with identical
names that perform slightly different operations. This is achieved by using virtual functions. A
virtual function can only be defined in a parent class. When a parent class declares a virtual
function, it is enabling any derived classes of the parent class the capability to create a different
function with the same name as the virtual function. If a derived class does not declare a new
function, the parent class function is used just like any other non-virtual function would be.
In essence, a virtual function allows a derived classes the option of overriding a parent class
function. Virtual functions must be called in a slightly different fashion than non-virtual functions.
VIRTUAL FUNCTIONS
An essential requirement of polymorphism is therefore the ability to refer to objects without any
regard to their classes. This necessitates the use of a single pointer variable to refer to the objects of
different classes. Here, we use the pointer to base class to refer to all the derived objects. But, we
just discovered that a base pointer, even when it is made to contain the address of derived class,
always executes the function in the base class. The compiler simply ignores the contents of the
pointer and chooses the member function that matches the type of the pointer.
How do we then achieve polymorphism? It is achieved using what is known as 'virtual' functions.
When we use the same function name in both the base and derived classes, the function in base class
is declared as virtual using the keyword virtual preceding its normal declaration. When a function is
made virtual, C++ determines which function to use at run time based on the type of object pointed
to by the base pointer, rather than the type of the pointer. Thus, by making the base pointer to point
to different objects, we can execute different versions of the virtual function. Program illustrates this
point.
#include<iostream.h>
class Base
{
void display() {cout<<” \n display Base “;}
void show() {cout << “\n show Base";}
}
class derived : public Base
{
public :
void display() {cout<<” \n display Derived “;}
void show() {cout << “\n show Derived";}
};
int Main()
{
Base B;
Derived D;
Base *bptr;
cout <<” \n bptr points toBase\n”;
bptr =&B;
bptr -> display(); //calls Base version
bptr -> show(); //calls Base version
cout « "\n\n bptr poini:s Derived\n";
bptr = &D;
bptr -> display(); // calls Base version
bptr -> show(); // calls Derived version
return 0;
}
The output of Program would be:
bptr points to Base
Display base
Show base
bptr points to Derived
Display base
Show derived
Note that When bptr is made to point to the object D, the statement
bptr -> display();
calls only the function associated with the Base (i.e. Base :: display( )), whereas the statement
bptr -> show();
calls the Derived version pf show(). This is because the function display () has not been made virtual
in the Base class.
One important point to remember is that, we must access virtual functions through the use of a
pointer declared as a pointer to the base class. Why can't we use the object name (with the dot
operator) the same way as any other member function to call the virtual functions? We can, but
remember, run time polymorphism is achieved only when a virtual function is accessed through a
pointer to the base class.
Let us take an example where virtual functions are implemented in practice. Consider a book shop
which sells both books and video-tapes. We can create a class known as media that stores the title
and price of a publication. We can then create two derived classes, one for storing the number of
pages in a book and another for storing the playing time of a tape.
Figure shows the class hierarchy for the book shop.
The class hierarchy for the book shop
The classes are implemented in Program. A function display() is used in all the classes to display the
class contents. Notice that the function display() has been declared virtual in media, the base class.
In the main program we create a heterogeneous list of pointers of type media as shown below:
media *list[2]; = { &book1; [1], &tape1};
The base pointers list[0] and list[1] are initialized with the addresses of objects bookl and tapel
respectively.
#include <iostream>
#include <cstring>
class media
{
protected :
char title [501;
float price;
public :
media (char *s, float a )
{
strcpy(title, s);
price = a;
}
media
book tape
virtual void display() { } / / empty virtual function
};
class book: public media
{
int pages;
public:
book(char *s, float a. int p) :media(s, a)
{
pages = p;
}
void display().;
};
class tape :public media
{
float time;
public:
tape(char * s, float a, float t):media(s, a)
{
time = t;
}
void display();
};
void book:: display()
{
cout << "\n Title: " << title;
cout << "\n Pages: " << pages;
cout<< “\n Price: "<< price;
}
void tape::display
{
cout <<” \n Title: "<< title;
cout <<”\n play time: " << time « "mins";
cout<< “\n Price: "<< price;
}
int main()
{
char *title = new char[30];
float price, time
int pages;
// Book details
cout <<”\n Enter Book Details \n”;
cout <<”\n Titles: “; cin >>title;
cout <<”\n Price : “; cin >>Price;
cout<< “\n pages: “ ; cin>> pages
book book1(title, price, pages)
// Tape details
cout <<”\n Enter Tape Details \n”;
cout <<”\n Titles: “; cin >>title;
cout <<”\n Price : “; cin >>Price;
cout<< “Play time (mins): “ ; cin>> time;
tape tape1(title, price, time);
media* list[2];
list[0] = &book1;
list[1] = &tape1;
cout<<”\n MEDIA DETALS”;
cout<<”\n ……BOOK…………”;
list[0]->display(); // display book details
cout<<”\n ……TAPE…………”;
list[0]->display(); // display Tape details
result 0;
}
The output of program
ENTER BOOK DETAILS
Title: Programming in ANSI C
Price: 88
Pages: 400
ENTER TAPE DETAILS
Title: Computing_Concepts
Price: 90
Play time (mi ns): 55
MEDIA DETAILS
…....BOOK...….
Title: Programming in ANSI C
Pages: 400
Price: 88
…….TAPE...….
Title: Computing_Concepts
Play time: 55mins
Price: 90
Rules for Virtual Functions
When virtual functions are created for implementing late binding, we should observe some basic
rules that satisfy the compiler requirements:
1. The virtual functions must be members of some class.
2. They cannot be static members.
3. They are accessed by using object pointers.
4. A virtual function can be a friend of another class.
5. A virtual function in a base class must be defined, even though it may not be used.
6. The prototypes of the base class version of a virtual function and all the derived class versions
must be identical. If two functions with the same name have different
prototypes, C++
considers them as overloaded functions, and the virtual function mechanism is
ignored.
7. We cannot have virtual constructors, but we can have virtual destructors.
8. While a base pointer can point to any type of the derived object, the reverse is not true. That is to
say, we cannot use a pointer to a derived class to access an object of the base type.
9. When a base pointer points to a derived class, incrementing or decrementing it will not make it to
point to the next object of the derived class. It is incremented or decremented only relative to its base
type. Therefore, we should not use this method to move the pointer to the next object.
10. If a virtual function is defined in the base class, it need not be necessarily redefined in the
derived class. In such cases, calls will invoke the base function.
PURE VIRTUAL FUNCTIONS
It is normal practice to declare a function virtual inside the base class and redefine it in the derived
classes. The function inside the base class is seldom used for performing any task. It only serves as
a placeholder. For example, we have not defined any object of class medial therefore the function
display() in the base class has been defined 'empty'. Such functions called "do-nothing" functions.
A "do-nothing" function may be defined as follows:
virtual void display() = 0;
Such functions are called pure virtual functions. A pure virtual function is a function declared in a
base class that has no definition relative to the base class. In such cases, the compiler requires each
derived class to either define the function or re declare it as a pure virtual function. Remember that a
class containing pure virtual functions cannot be used declare any objects of its own. As stated
earlier, such classes are called abstract base c/asses. The main objective of an abstract base class-is
to provide some traits to the derived classes and to create a base pointer required for achieving run
time polymorphism.
Summary
When we use the same function name in both the base and derived classes, the function in
base class is declared as virtual using the keyword virtual preceding its normal declaration.
When a function is made virtual, C++ determines which function to use at run time based on
the type of object pointed to by the base pointer, rather than the type of the pointer
Remember that a class containing pure virtual functions cannot be used declare any objects
of its own. As stated earlier, such classes are called abstract base c/asses. The main objective
of an abstract base class-is to provide some traits to the derived classes and to create a base
pointer required for achieving run time polymorphism.
Questions
1. What do you, mean by Virtual function? Why do we need virtual functions
2. explain pure virtual function
3. distingwish between virtual functions and pure virtual function
UNIT I
Lesson 19
POLYMORPHISM
Objective
Concept of polymorphism
Static and Dynamic Binding
INTRODUCTION
Polymorphism is one of the crucial features of OOP. It simply means 'one name, multiple forms'.
you have already seen how the concept of polymorphism is implemented using the overloaded
functions and operators. The overloaded member functions are selected for invoking by matching
arguments, both type and number. This information is known to the compiler at the compile time
and, therefore, compiler is able to select the appropriate function for a particular .Call at the compile
time itself. This is called early binding or static binding or static linking. Also known as compile
time polymorphism, early binding simply mean that an object is bound to its function call at compile
time.
It would be nice if the appropriate member function could be selected while the program is running.
This is known as run time polymorphism. How could it happen? C++ supports a mechanism known
as virtual function to achieve run time polymorphism.
Achieving polymorphism
Polymorphism
Function overloading
Operator overloading
Compile time polymorphism
Run time polymorphism
Virtual functions
At run time, when it is known what class objects are under consideration,. the appropriate version of
the function is invoked. Since the function is linked with a particular class much iter after the
compilation, this process is termed as late binding. It is also known as dynamic binding because the
selection of the appropriate function is done dynamically at run time.
Dynamic binding is one of the powerful features of C++. This requires the use of pointers to objects.
We shall discuss in detail how the object pointers and virtual functions are used to implement
dynamic binding.
Static and Dynamic Binding
In a strongly typed programming languages you typically have to declare variables prior to their use.
This also implies the variable's definition where the compiler reserves space for the variable. For
example, in Pascal expressions like
var i : integer;
declares variable i to be of type integer. Additionally, it defines enough memory space to hold an
integer value.
With the declaration we bind the name i to the type integer. This binding is true within the scope in
which i is declared. This enables the compiler to check at compilation time for type consistency. For
example, the following assignment will result in a type mismatch error when you try to compile it:
var i : integer;
...
i := 'string';
We call this particular type of binding “static” because it is fixed at compile time.
Definition (Static Binding) If the type T of a variable is explicitly associated with its name N by
declaration, we say, that N is statically bound to T. The association process is called static binding.
There exist programming languages, which are not using explicitly typed variables. For example,
some languages allow to introduce variables once they are needed:
... /* No appearance of i */
i := 123 /* Creation of i as an integer */
The type of i is known as soon as its value is set. In this case, i is of type integer since we have
assigned a whole number to it. Thus, because the content of i is a whole number, the type of i is
integer.
Definition (Dynamic Binding) If the type T of a variable with name N is implicitly associated by its
content, we say, that N is dynamically bound to T. The association process is called dynamic
binding.
Both bindings differ in the time when the type is bound to the variable. Consider the following
example, which is only possible with dynamic binding:
if somecondition( ) == TRUE then
n := 123
else
n := 'abc'
The type of n after the if statement depends on the evaluation of somecondition( ). If it is TRUE, n
is of type integer whereas in the other case it is of type string.
Polymorphism allows an entity (for example, variable, function or object) to take a variety of
representations. Therefore we have to distinguish different types of polymorphism, which will be
outlined here.
The first type is similar to the concept of dynamic binding. Here, the type of a variable depends on
its content. Thus, its type depends on the content at a specific time:
v := 123 /* v is integer */
... /* use v as integer */
v := 'abc' /* v "switches" to string */
... /* use v as string */
Definition (Polymorphism (1)) The concept of dynamic binding allows a variable to take different
types dependent on the content at a particular time. This ability of a variable is called
polymorphism. Another type of polymorphism can be defined for functions. For example, suppose
you want to define a function isNull( ) which returns TRUE if its argument is 0 (zero) and FALSE
otherwise. For integer numbers this is easy:
boolean isNull(int i)
{
if (i == 0) then
return TRUE
else
return FALSE
endif
}
However, if we want to check this for real numbers, we should use another comparison due to the
precision problem:
boolean isNull(real r) {
if (r < 0.01 and r > -0.99) then
return TRUE
else
return FALSE
endif
}
In both cases we want the function to have the name isNull. In programming languages without
polymorphism for functions we cannot declare these two functions because the name isNull would
be doubly defined. Without polymorphism for functions, doubly defined names would be
ambiguous. However, if the language would take the parameters of the function into account it
would work. Thus, functions (or methods) are uniquely identified by:
the name of the function (or method) and
the types of its parameter list.
Since the parameter list of both isNull functions differ, the compiler is able to figure out the correct
function call by using the actual types of the arguments:
var i : integer
var r : real
i = 0
r = 0.0
...
if (isNull(i)) then ... /* Use isNull(int) */
...
if (isNull(r)) then ... /* Use isNull(real) */
Definition (Polymorphism (2)) If a function (or method) is defined by the combination of
its name and
the list of types of its parameters
we speak of polymorphism. This type of polymorphism allows us to reuse the same name for
functions (or methods) as long as the parameter list differs. Sometimes this type of polymorphism is
called overloading.
The last type of polymorphism allows an object to choose correct methods. Consider the function
move( ) again, which takes an object of class Point as its argument. We have used this function with
any object of derived classes, because the is-a relation holds.
Now consider a function display( ) which should be used to display drawable objects. The
declaration of this function might look like this:
display(DrawableObject o) {
...
o.print( )
...
}
We would like to use this function with objects of classes derived from DrawableObject:
Circle acircle
Point apoint
Rectangle arectangle
display(apoint) /* Should invoke apoint.print( ) */
display(acircle) /* Should invoke acircle.print( ) */
display(arectangle) /* Should invoke arectangle.print( ) */
The actual method should be defined by the content of the object o of function display( ). Since this
is somewhat complicated, here is a more abstract example:
class Base {
attributes:
methods:
virtual foo( )
bar( )
}
class Derived inherits from Base {
attributes:
methods:
virtual foo( )
bar( )
}
demo(Base o) {
o.foo( )
o.bar( )
}
Base abase
Derived aderived
demo(abase)
demo(aderived)
In this example we define two classes Base and Derived. Each class defines two methods foo( ) and
bar( ). The first method is defined as virtual. This means that if this method is invoked its
definition should be evaluated by the content of the object.
We then define a function demo( ) which takes a Base object as its argument. Consequently, we can
use this function with objects of class Derived as the is-a relation holds. We call this function with a
Base object and a Derived object, respectively.
Suppose, that foo( ) and bar( ) are defined to just print out their name and the class in which they are
defined. Then the output is as follows:
foo( ) of Base called.
bar( ) of Base called.
foo( ) of Derived called.
bar( ) of Base called.
Why is this so? Let's see what happens. The first call to demo( ) uses a Base object. Thus, the
function's argument is ``filled'' with an object of class Base. When it is time to invoke method foo( )
it's actual functionality is chosen based on the current content of the corresponding object o. This
time, it is a Base object. Consequently, foo( ) as defined in class Base is called.
The call to bar( ) is not subject to this content resolution. It is not marked as virtual. Consequently,
bar( ) is called in the scope of class Base.
The second call to demo( ) takes a Derived object as its argument. Thus, the argument o is filled with
a Derived object. However, o itself just represents the Base part of the provided object aderived.
Now, the call to foo( ) is evaluated by examining the content of o, hence, it is called within the scope
of Derived. On the other hand, bar( ) is still evaluated within the scope of Base.
Definition (Polymorphism (3)) Objects of superclasses can be filled with objects of their subclasses.
Operators and methods of subclasses can be defined to be evaluated in two contextes:
1. Based on object type, leading to an evaluation within the scope of the superclass.
2. Based on object content, leading to an evaluation within the scope of the contained
subclass.
“So now we will derive a program in C++ to explain how ‘polymorphism’ works….”
Polymorphism allows more than one function to have the same name, provided all functions are
either distinguishable by the typing or the number of their parameters. Using a function name more
than once is sometimes referred to as overloading the function name.
Here's an example:
#include<iostream>
using namespace std;
int average(int first_number, int second_number, int
third_number);
int average(int first_number, int second_number);
/* MAIN PROGRAM: */
int main( )
{
int number_A = 5, number_B = 3, number_C = 10;
cout << "The integer average of " << number_A << " and ";
cout << number_B << " is ";
cout << average(number_A, number_B) << ".\n\n";
cout << "The integer average of " << number_A << ", ";
cout << number_B << " and " << number_C << " is ";
cout << average(number_A, number_B, number_C) << ".\n";
return 0;
}
/* END OF MAIN PROGRAM */
/* FUNCTION TO COMPUTE INTEGER AVERAGE OF 3 INTEGERS: */
int average(int first_number, int second_number, int third_number)
{
return ((first_number + second_number + third_number)/3);
}
/* END OF FUNCTION */
/* FUNCTION TO COMPUTE INTEGER AVERAGE OF 2 INTEGERS: */
int average(int first_number, int second_number)
{
return ((first_number + second_number) / 2);
}
/* END OF FUNCTION */
When the same function is repeatedly executed for different purposes, as mentioned in above
explanation, the function is then supposed to be overloaded.
Summary
Polymorphism is one of the crucial features of OOP. It simply means 'one name, multiple
forms'. It would be nice if the appropriate member function could be selected while the
program is running. This is known as run time polymorphism.
At run time, when it is known what class objects are under consideration,. the appropriate
version of the function is invoked. Since the function is linked with a particular class much
iter after the compilation, this process is termed as late binding. It is also known as dynamic
binding because the selection of the appropriate function is done dynamically at run time.
The overloaded member functions are selected for invoking by matching arguments, both
type and number. This information is known to the compiler at the compile time and,
therefore, compiler is able to select the appropriate function for a particular .Call at the
compile time itself. This is called early binding or static binding or static linking.
Questions
1. What do you mean by polymorphism? explain
2 Discuss the different ways by which we can access public member function of an
object
3 How does polymorphism promote extensibility?
UNIT ILESSON 20
VIRTUAL BASE CLASSES, NESTING OF CLASS
Objective
Abstract Classes
Virtual Base Classes
Member Classes
ABSTRACT CLASSES
An abstract class is one that is not used to create objects. An abstract class is designed only to act as
a base class (to be inherited by other classes). It is a design concept in program development and
provides a base upon which other classes may be built. In the previous example, the student class is
an abstract class since it was not used to create any objects.
Basic abstract classes are something very similar to the class CPolygon of our previous example.
The only difference is that in our previous example we have defined a valid area() function for
objects that were of class CPolygon (like object poly), whereas in an abstract base class we could
have simply left without defining this function by appending =0 (equal to zero) to the function
declaration.
The class CPolygon could have been thus:
// abstract class CPolygon
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
Notice how we have appended =0 to virtual int area (void) instead of specifying an implementation
for the function. This type of function is called a pure virtual function, and all classes that contain a
pure virtual function are considered abstract base classes.
The greatest difference of an abstract base class is that instances (objects) of it cannot be created, but
we can create pointers to them. Therefore a declaration like:
CPolygon poly;
would be incorrect for the abstract base class declared above. Nevertheless the pointers:
CPolygon * ppoly1;
CPolygon * ppoly2
are be perfectly valid. This is because the pure virtual function that it includes is not defined and it is
impossible to create an object if it does not have all its members defined. Nevertheless a pointer that
points to an object of a derived class where this function has been defined is perfectly valid.
Here you have the complete example:
// virtual members
#include <iostream.h>
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
return 0;
}
output
20
10
If you review the program you will notice that we can refer to objects of different classes using a
unique type of pointer (CPolygon*). This can be tremendously useful. Imagine, now we can create a
function member of CPolygon that is able to print on screen the result of the area() function
independently of what the derived classes are.
// virtual members
#include <iostream.h>
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() << endl; }
};
class CRectangle: public CPolygon {
public:
int area (void)
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main()
{
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
return 0;
}
Output
20
10
Remember that this represents a pointer to the object whose code is being executed. Abstract classes
and virtual members grant to C++ the polymorphic characteristics that make object-oriented
programming such a useful instrument. Of course we have seen the simplest way to use these
features, but imagine these features applied to arrays of objects or objects assigned through dynamic
memory.
VIRTUAL BASE CLASSES
We have just discussed a situation which would require the use of both the multiple and multilevel
inheritance. Consider a situation where all the three kinds of inheritance, namely, multilevel,
multiple and hierarchical inheritance, are involved. This is illustrated in fig. The 'child' has two
direct base classes 'parent1' and 'parent2' which themselves nave a common base class 'grandparent'.
The 'child' inherits the traits of 'grandparent' via two separate paths. It can also inherit directly as
shown by the broken line. The 'grandparent' is sometimes referred to as indirect base class.
Multipath inheritance
Inheritance by the 'child' as shown in Fig. above might pose some problems. All the public
and protected members of, grandparent' are inherited into 'child' twice, first via 'parent1' and again
via 'parent2'. This means, 'child' would have duplicate sets of the members inherited from
'grandparent'. This introduces ambiguity and should be avoided.
Grandparent
Parent 2Parent 1
Child
The duplication of inherited members due to these multiple paths can be avoided by making
the common base class (ancestor class) as virtual base class while declaring the direct or
intermediate base classes which is shown as follow:
class A // grandparent
{
… …
… …
};
class B1 : virtual public A // parentl
{
… …
… …
};
class B2 : public virtual A // parent2
{
… …
… …
};
class C : public BI, public B2 // child
{
… … // only one copy of A
… … // will be inherited
};
When a class is made a virtual base class, C++ takes necessary care to see that only one
copy of that class is inherited, regardless of how many inheritance paths exist between virtual base
class and a derived class.
Note: The keywords virtual and public may be used in either order.
For example, consider again the student results processing system discussed. Assume that the class
sports derives the roll number from the class student. Then, inheritance relationship will be as
shown below.
As virtual base class As virtual base class
Virtual base class
A program to implement the concept of virtual base class is illustrated below:
VIRTUAL BASE CLASS
#include <iostream>
using namespace std;
class student
{
protected:
int roll_number;
public:
void get_number(int a)
{
roll_number = a;
}
void put_number (void)
{
Sports
Student
Test
Result
cout << “Roll No: “ << roll_number << “\n”;
}
};
class test : virtual public student
{
protected:
float part1, part2;
public:
void get_marks(float x, float y)
{
part1 = x; part2 = y;
}
void put_marks(void)
{
cout << “Marks obtained: “ << “\n”
<< “Part1 = “ << “\n”
<<”Part2 = “ << “\n”;
}
};
class sports : public virtual student
{
protected:
float score;
public:
void get_score(float s)
{
score = s;
}
void put_score(void)
{
cout << “Sports wt: “ << score << “\n\n”;
}
};
class result : public test, public sports
{
float total;
public:
void display(void);
};
void result :: display(void)
{
total = part1 + part2 + score;
put_number();
put_marks();
put_score();
cout << “Total Score: “ << total << “\n”;
}
int main()
{
result student_!;
student_1.get_number(678);
student_1.get_marks(30.5, 25.5);
student_1.get_score(7.0);
student_1.display();
return 0;
}
The output of program would be:
Roll No: 678
Marks obtained:
Part1 = 30.5
Part2 = 25.5
Sport wt: 7
Total Score: 63
MEMBER CLASSES: NESTING OF CLASSES
Inheritance is the mechanism of deriving certain properties of one class into another. We
have seen in detail how this is implemented using the concept of derived classes. C++ supports yet
another way of inheriting properties of one class into another. This approach takes a view that an
object can be a collection of many other objects. That is, a class can contain objects of other classes
as its members as shown below:
class alpha { };
class beta { };
c1ass gamma
{
alpha a; // a is an object of alpha class
beta b; // b is an object of beta class
……
} ;
All objects of gamma class will contain the objects a and b. This kind of relationship is called
containership or nesting. Creation of an object that contains another object is very different than the
creation of an independent object. An independent object is created by it’s constructor when it is
declared with arguments. On the other hand, a nested object is created in two stages. First, the
member objects are created using their respective constructors and then the other 'ordinary' members
are created. This means, constructors of all the member objects should be called before its own
constructor body is executed. This is accomplished using an initialization list in the constructor of
the nested class.
Example:
class gamma
{
……
alpha a; // a is object of alpha
beta b; // b is object of beta
public:
gamma (arg1ist): , a(arg1istl), b(arg1ist2)
{
// constructor body
}
};
arglist is the list of arguments that is to be supplied when a gamma object is defined. These
parameters are used for initializing the members of gamma. arglistl is the argument list for, the
constructor of a and arglist2 is the argument list for the constructor of b. arglistl and arglist2 may or
may not use the arguments from arglist. Remember, a(arglistl) and b(arglist2) are function calls and
therefore the arguments do not contain the data types. They are simply variables or constants.
Example:
gamma (int x, int y, float z) : a(x), b(x,z)
{
Assignment section (for ordinary other members)
}
We can use as many member objects as are required in a class. For each member object we
add a constructor call in the initializer list. The constructors of the member objects are called in the
order in which they are declared in the nested class.
Summary
An abstract class is one that is not used to create objects. An abstract class is designed
only to act as a base class (to be inherited by other classes).
C++ supports yet another way of inheriting properties of one class into another. This
approach takes a view that an object can be a collection of many other objects. That
is, a class can contain objects of other classes as its members
Questions
1. What is virtual base class?
2. what do you mean by abstract class?
3. when do we make a class virtual?
UNIT I
LESSON 21
STREAMS
Objective
C++ streams
C++ stream class
INTRODUCTION
Every program takes some data as input and generates processed data as output following the
familiar input-process-output cycle. It is, therefore, essential to know how to provide the input data
and how to present the results in a desired form. We have, in the earlier chapters, used cin and cout
with the operators >> and << for the input and output operations. But we have not so far discussed as
to how to control the way the output is printed. C++ supports a rich set of I/O functions and
operations to do this. Since these functions use the advanced features of C++ (such as classes,
derived classes and virtual functions), we need to know a lot about them before really implementing
the C++ I/O operations.
Remember, C++ supports all of C's rich set of I/O functions. We can use any of them in the C++
programs. But we restrained from using them due to two reasons. First, I/O methods in C++ support
the concepts of OOP and secondly, I/O methods in C cannot handle the user-defined data types such
as class objects.
c++ uses the concept of stream and stream classes to implement its I/O operations with the console
and disk files. We will discuss in this chapter, how stream classes support the
console- oriented input-output operations. File-oriented I/O operations will be discussed in
the next chapter.
C++ STREAMS
The I/O system in C++ is designed to work with a wide variety of devices including terminals, disks,
and tape drives. Although each device is very different, the I/O system supplies an interface to the
programmer that is independent of the actual device being accessed. This interface is known as
stream.
A stream is a sequence of bytes. It acts either as a source from which the input data can be obtained
or as a destination to which the output data can be sent. The source stream that provides data to the
program is called the input stream and the destination stream that receives output from the program
is called the output stream. In other words, a program extracts the bytes from an input stream and
inserts bytes into an output stream as illustrated in Fig. 10.1.
output stream
insertion into
Output stream
Fig. Data streams
The data in the input stream can come from the keyboard or any other storage device. Similarly, the
data in the output stream can go to the screen or any other storage device. As mentioned earlier, a
stream acts as an interface between the program and the inputJoutput device. Therefore, a C++
program handles data (input or output) independent of the devices used.
C++ contains several pre-defined streams that are automatically opened when a program begins its
execution. These include cin and cout which have been used very often in our
earlier programs. We know that cin represents the input stream connected to the standard input
device (usually the keyboard) and cout represents the output stream connected to the standard output
device (usually the screen). Note that the keyboard and the screen are default options. We can
redirect streams to other devices or files, if necessary.
Buffers and Synchronization
“What is a buffer?..Lets understand the working of a buffer memory.”
A buffer is a temporary holding area in memory which acts as an intermediary between a program
and a file or other I/0 device. Information can be transferred between a buffer and a file using large
chunks of data of the size most efficiently handled by devices like disc drives. Typically, devices
like discs transfer information in blocks of 512 bytes or more, while program often processes
information one byte at a time. The buffer helps match these two desperate rates of information
transfer. On output, a program first fills the buffer and then transfers the entire block of data to a
hard disc, thus clearing the buffer for the next batch of output. C++ handles input by connecting a
buffered stream to a program and to its source of input. similarly, C++ handles output by connecting
a buffered stream to a program and to its output target.
When we operate with file streams, these are associated to a buffer of type streambuf.. For example,
with an out stream, each time the member function put (write a single character) is called, the
character is not written directly to the physical file with which the stream is associated. Instead of
that, the character is inserted in the buffer for that stream.
When the buffer is flushed, all data that it contains is written to the physic media (if it is an out
stream) or simply erased (if it is an in stream). This process is called synchronization and it takes
place under any of the following circumstances:
When the file is closed: before closing a file all buffers that have not yet been completely written or
read are synchronized.
When the buffer is full: Buffers have a certain size. When the buffer is full it is automatically
synchronized.
Explicitly with manipulators: When certain manipulators are used on streams a synchronization
takes place. These manipulators are: flush and endl.
Explicitly with function sync(): Calling member function sync() (no parameters) causes an
immediate syncronization. This function returns an int value equal to -1 if the stream has no
associated buffer or in case of failure
C++ STREAM CLASSES
The C++ I/O system contains a hierarchy of classes that are used to define various streams to deal
with both the console and disk files. These classes are called stream classes. Figure shows
the hierarchy of the stream classes used for input and output operations with the console unit.
pointer
Input output
Fig. Stream classes for console I/O operations
These classes are declared in the header file iostream. This file should be included in all the
programs that communicate with the console unit.
As seen in the Fig. ios is the base class for istream (input stream) and ostream (output stream) which
are, in turn, base classes for iostream (input/output stream). The class ios is declared as the virtual
base class so that only one copy of its members are inherited by the iostream.
The class ios provides the basic support for formatted and unformatted I/O operations. The class
istream provides the facilities for formatted and unformatted input while the class ostream (through
inheritance) provides the facilities for formatted output. The class iostream provides the facilities for
handling both input and output streams. Three classes, namely, istream- withassign, ostream-
withassign, and iostream- withassign add assignment operators to these classes. Table gives the
details of these classes.
Table
Class name Contents
1. IOS Contains basic facilities that are (General
(input/output stream used by all other input and output
ios
streambufistream ostream
iostream
ostream_withassigniostream_withassignistream_withassign
class) . classes.
Also contains a pointer to a buffer object (streambuf object).
Declares constants and functions that are necessary for handling formatted input and output
operations.
2. istream inherits the properties of ios.
(input stream) Declares input functions such as get(), getline()
and read().
Contains overloaded extraction operator.
3. ostream (output stream) inherits the properties of ios.
Declares output functions put() and write().
4. iostream (input / output stream) inherits the properties of ios istream and
ostream through multiple inheritance ,and thus
contains all the input and output functions.
5. streambuf Provides an interface to physical devices
through buffers.
Acts as a base for filebuf class used ios files.
Summary
C++ supports all of C's rich set of I/O functions.
First, I/O methods in C++ support the concepts of OOP and secondly, I/O methods in C
cannot handle the user-defined data types such as class objects.
The I/O system in C++ is designed to work with a wide variety of devices including
terminals, disks, and tape drives.
A stream is a sequence of bytes. It acts either as a source from which the input data can
be obtained or as a destination to which the output data can be sent.
The source stream that provides data to the program is called the input stream and the
destination stream that receives output from the program is called the output stream.
A buffer is a temporary holding area in memory which acts as an intermediary between a
program and a file or other I/0 device.
When we operate with file streams, these are associated to a buffer of type streambuf
When the buffer is flushed, all data that it contains is written to the physic media (if it is
an out stream) or simply erased (if it is an in stream)
The C++ I/O system contains a hierarchy of classes that are used to define various
streams to deal with both the console and disk files.
ios is the base class for istream (input stream) and ostream (output stream) which are, in
turn, base classes for iostream (input/output stream).
Question
What is stream?. Explain C++ stream classes?
Describe briefly the features of I/O system supported by C++.
UNIT I
LESSON 22
STREAMS II
Objective
Put & Get Function
Getline & Write function
put() and get() Functions
The classes istream and ostream define two member functions get() and put() respectively to handle
the single character input/output operations. There are two types of get() functions. We can use both
get(char *) and get (void) prototypes to fetch a character including the blank space, tab and the
newline character. The get (char *) version assigns the input character to its argument and the get
(void) version returns the input character.
Since these functions are members of the input/output stream classes, we must invoke them using an
appropriate object.
Example:
char c;
cin.get(c) ; // get a character from keyboard and assign it to c
while(c != '\n')
{
cout « c; // display the character on screen
cin.get(c); // get another character
}
This code reads and displays a line of text (terminated by a newline character). Rememter, the
operator >> can also be used to read a character but it will skip the white spaces and newline
character. The above while loop will not work properly if the statement
ci n >> c;
is issued in place of
cin.get(c) ;
The get(void) version is used as follows:
cha r c;
c=cin/get(); // cin.get(c); replaced
…………
…………
The value returned by the function get() is assigned to the variable c.
The function put(), a member of ostream class, can be used to output a line of text, character by
character.
For example,
cout.put( ‘x’);
displays the character x and
cout. put (ch) ;
displays the value of variable ch.
The variable ch must contain a character value. We can also use a number as an argument to the
function put(). For example,
cout. put (68) ;
displays the character D. This statement will convert the int value 68 to a char value display the
character whose ASCII value is 68.
The following segment of a program reads a line of text from the keyboard and displays on the
screen.
char c;
cin.get(c); / / read a character
while (c ! = ‘ \n ‘ )
{
cout.put(c) ;
cin.get(c); / / display the character on screen
}
Program illustrates the use of these two character-handling functions.
# include <iostream>
int main()
{
int count = 0;
char c;
cout << "INPUT TEXT\n”;
cin.get{c);
while(c!=’\n’)
{
cout.put(c);
count++ ;
cin.get( c);
}
cout <<"\n Number of characters = “<< cout << “\n”;
return 0;
}
Input
Object Oriented Programming
Output
Object Oriented Programming
Number of characters = 27
Getline() and write() Functions
We can read and display a line of text more efficiently using the line-oriented input / output
functions getline() and write(). The getline() function reads a whole line of text that ends with a
newline character (transmitted by the RETURN key). This function can be invoked by using the
object cin as follows:
This function call invokes the function getline() which reads character input into the variable line.
The reading is terminated as soon as either the newline character '\n' is encountered or size-1
characters are read (whichever occurs first). The newline character is read but not saved. Instead, it
is replaced by the null character. For example, consider the following code:
char name [20] ;
cin.getl i ne(name, 20);
Assume that we have given the following input through the keyboard:
Bjarne Stroustrup <press RETURN>
This input will be read correctly and assigned to the character array name. Let us suppose the input is
as follows:
Object Oriented Programming <press RETURN>
In this case, the input will be terminated after reading the following 19 characters:
Object Oriented Pro
Remember, the two blank spaces contained in the string are also taken into account. We can also
read strings using the operator» as follows:
cin >> name;
But remember cin can read string that do not contain white spaces. This means that cin
Cin.getline(line,size);
Can read just one word and not a series of Word such as “Bjarne Stroustrup”. But it can read the
following string correctly.
Bjarne_Stroustrup
After reading the string, cin automatically adds the terminating null character to the character array.
#include <iostream.h>
int main()
{
int size = 20;
char city[20];
cout<<” enter city name : \n”;
cin>> city;
cout<<”city name:”<<city<<”\n\n”;
cout<<” enter city name again : \n”;
cin.getline(city, size);
cout<<”city name now : “ <<city << “\n\n”;
cout<<”enter another city name:\n”;
cin.getline(city, size);
cout<<”new city name :” << city << “\n\n”;
return 0;
}
output
first run
enter city name:
Delhi
City name: Delhi
enter city name again:
city name now:
enter another city name:
chennai
new city name: chennai
Second run
enter city name:
New Delhi
City name: New
enter city name again:
city name now: Delhi
enter another city name:
Greater Mumbai
new city name: Greater Mumbai
During first run, the newline character '\n' at the end of "Delhi" which is waiting in the input queue is
read by the getline() that follows immediately and therefore it does not wait for any response to the
prompt 'Enter city name again:'. The character '\n' is read as an empty line. During the second run,
the word "Delhi" (that was not read by cin) is read by the function getline() and, there(ore, here
again it does not wait for any input to the prompt 'Enter city name again:'. Note that the line of text
"Greater Bombay" is correctly read by the second cin.getline(city,size); statement.
Write() function displays an entire line and has the following form:
Cout.write (line, size)
First argument line represents the name of the string to be displayed and the second argument size
indicates the number of characters to display. Note that it does not stop displaying the Characters
automatically when the null character is encountered. If the size is greater than the «line, then it
displays beyond the bounds of line. Program illustrates how write() displays a string.
Displaying string with Write()
#include<iostream,h>
#include<string.h>
int Main()
{
char * string1 = “C++”
char * string2 = “Programming”;
int m = strlen(string1);
int n = strlen(string2);
for(int i=1; i<n; i++)
{
cout.write(string2,i);
cout<< “\n”;
}
for(int i=n; i>0; i--)
{
cout.write(string2,i);
cout<< “\n”;
}
cout.write(string1,m).write(string2,n);
cout<< “\n”;
cout. write(string1,10);
return 0;
}
output
P
Pr
Pro
Prog
Progr
Progra
Program
Programm
Programmi
Programmin
Programming
Programmin
Programmi
Programm
Program
Progra
Progr
Prog
Pro
Pr
P
C++ Programming
C++ Progr
The last line of the output indicates that the statement
cout.write(string1, 10);
displays more characters than what is contained in stringl.
It is possible to concatenate two strings using the write() function. The statement
cout.write(string1, m).write(string2, n);
is equivalent to the following two statements:
cout.write(string1, m);
cout.write(string2, n);
Summary
The classes istream and ostream define two member functions get() and put() respectively
to handle the single character input/output operations.
The function put(), a member of ostream class, can be used to output a line of text,
charac-ter by character.
We can read and display a line of text more efficiently using the line-oriented input /
output functions getline() and write().
The getline() function reads a whole line of text that ends with a newline character
Write() function displays an entire line
Question
Discuss the various forms of get() function supported by the input stream. How are they used?
How do the following two statements differ in operation?
cin>>c;
cin.get(c);
Both cin & getline() function can be used for reading a string. Comment?
UNIT ILesson 23
Tutorial on polymorphism and Streams
UNIT ILESSON 24
WORKING WITH FILES
Objectives Opening a file with constructors File stream classes
INTRODUCTIONMany real-life problems handle large volumes of data and, in such situations, we need to use
some devices such as floppy disk or hard disk to store the data. The data is stored in these devices
using the concept of files. A file is a collection of related data stored in a particular area on the disk,
Programs can be designed to perform the read and write operations on these files. A program
typically involves either or both of the following kinds of data communication:
1. Data transfer between the console unit and the program.
2. Data transfer between the program and a disk file.
This is illustrated in Fig. below
External memory
Programfile interaction
Write Data Read data(to files) (from files)
Internal Memory
cout<< Console –program
(put data interaction to screen)
cin>>(get data fromkeyboard)
Data files
Program + Data
Sceen
KeyboardConsole – program – file interaction
We have already discussed the technique of handling data communication between the
console unit and the program. In this chapter, we will discuss various methods available for storing
and retrieving the data from files.
The I/O system of C++ handles file operations, which are very much similar to the console
input and output operations. It uses file streams as an interface between the programs and the files.
The stream that supplies data to the program is known as input stream and the one that receives data
from the program is known as output stream. In other words, the input stream extracts (or reads) data
from the file and the output stream inserts (or writes) data to the file. This is illustrated in Fig. below
Input streamRead data Data input
Output stream Data O/P
Write data
File input and output streams
The input operation involves the creation of an input stream and linking it with the program and the
input file. Similarly, the output operation involves establishing an output stream with the necessary
links with the program and the output file.
ProgramDisk files
Iostream file
Fstream file
Fig. Stream classes for file operations
CLASSES FOR FILE STREAM OPERATIONS
The I/O system of C++ contains a set of classes that define the file handling methods. These include
ifstream, ofstream and fstream. These classes are derived from fstreambase and from the
corresponding iostream class as shown in Fig. 11.3. These classes, designed to manage the disk files
are declared in fstream and therefore we must include this file in any program that uses files.
Table shows the details of file stream classes. Note that these classes contain many more features.
Class content
ifstream
Fstream base
filebufofstreamfstream
ios
ostreamstreambuf
iostream
istream
Filebuf Its purpose is to set the file buffers to read and write. Contains Openprot constant used in the open() of file stream classes. Also contain close() and open() as member.
fstreambase Provides operations common to the file streams. Serves as a base forfstream, if stream and of stream class. Contains open() and close()functions.
ifstream Provides input operations. Contains openO with default input mode.Inherits the functions getO, getlineO, readO, seekgO and tellgOfunctions from istream.
Ofstream Provides output operations. Contains openO with default output mode. Inheritsput(), see}(p(), !~llP(),. and writ~(), functions from ostream.
Fstream Provides support for simultaneous input and output operations. Contains open() with default input mode. Inherits all the functions from istream and ostream classes through iostream.
OPENING AND CLOSING A FILE
If we want to use a disk file, we need to decide the following things about the file and itsintended use:
1. Suitable name for the file. 2. Data type and structure. 3. Purpose.4. Opening method.
The filename is a string of characters that make up a valid filename for the operating system. It may contain two parts, a primary name and an optional period with extension. Examples:
Input.data Test.doc INVENT.ORY Studentsalary OUTPUT
As stated earlier, for opening a file, we must first create a file stream and then link it to the filename.
A file stream can be defined using the classes ifstream, of stream, and ofstream that are contained in
the header file (stream. The class to be used depends upon the purpose, that is, whether we want to
read data from the file or write data to it. A file can be opened in two ways:
Using the constructor function of the class. Using the member function open() of the class.
The first method is useful when we use only one file in the stream. The second method is used when we want to manage multiple files using one stream.
Opening Files Using Constructor
We know that a constructor is used to initialize an object while it is being created. Here, a filename is used to initialize the file stream object. This involves the following steps:
1. Create a file stream object to manage the stream using the appropriate class. That is to say, the class ofstream is used to create the output stream and the class ifstream to create the input stream.
2. Initialize the file object with the desired filename.
For example, the following statement opens a file named "results" for output:
ofstream outfile("results"); / / output only
This creates outfile as an ofstream object that manages the output stream. This object can be any
valid C++ name such as o_file, myfile or fout. This statement also opens the file results and attaches
it to the output stream outfile. This is illustrated in Fig.
DiskOutput stream
Input stream
Two file streams working on separate files
Similarly, the following statement declares infile as an if stream object and attaches it to the file data for reading (input),
Ifstream infile ("data") ; // input only
The program m~y contain statements like:
program
Results file
Data file
outfile << "TOTAL"; outfile <<sum; infile >>number;infile >>string;
program1
put dataoutfile
program2 get data
infile
Two file streams working on one file
We can also-use the same file for both reading and writing data as shown in Fig. 11.5. The programs would contain the following statements:
Program 1
--------------------ofstream outfile ("salary"); // creates outfi1e and connects
// "salary" to it----------------------Program 2--------------------ifstream infile ("salary"); // creates infi1e and connects
// "salary" to it----------------------
The connection with a file is closed automatically when the stream object expires (when the program
terminates). In the above statement, when the program l is terminated, the salary file is disconnected
from the outfile stream. Similar action takes place when the program 1 terminates.
………….………….
……………………………..
Salary file
Instead of using two programs, one for writing data (output) and another for reading data (input), we
can use a single program to do both the operations on a file.
Example.
--------------------
outfile.close(); // Disconnect salary from outfileifstream infile ("sa1ary") ; // and connect to infile
--------------------
infile.closeO; // Disconnect salary from infile
Although we have used a single program, we created two file stream objects, outfile (to put data to
the file) and infile (to get data from the file). Note that the use of a statement like
outfile.close();
disconnects the file salary from the output stream outfile. Remember, the object outfile still exists
and the salary file may again be connected to outflle later or to any other stream. In this example,
we are connecting the salary file to infile stream to read data.
Program uses a single file for both writing and reading the data. First, it takes data from the
keyboard and writes it to the file. After the writing is completed, the file is closed. The program
again opens the same file, reads the information already written to it and displays the same on the
screen.
Working with single file
// Creating files with constructor function
#include <iostream.h>#include <fstream.h>int main(){ofstream outf("ITEM");cout « "Enter item name:" ; char name [30] ;
cin >> name;outf << name « "\n";cout << "Enter item cost:"; float cost;cin >> cost;outf << cost « "\n.";outf.close();ifstream inf ("ITEM") ;inf>> name; inf >>cost;cout << "\n.";cout << "Item name:” <<name <<”\n”;cout « "Iterm cost:” << cost <<”\n”;inf.close();return 0;}
The output of Program would be:
Enter itern name: CD-ROM Enter item cost : 250
Item name:CD-ROM Item cost:250
When a file is opened for writing only, a new file is created if there is no file of that name. If a file
by that name exists already, then its contents are deleted and the file is presented as a dean file. We
shall discuss later how to open an existing file for updating it without losing its original contents.
Opening Files Using open()
As stated earlier, the function open() can be used to open multiple files that use the same stream
object. For example, we may want to process a set of files sequentially. In such cases, we may create
a single stream object and use it to open each file in turn. This is done as follows
Example:
File-stream-class stream-objects;Stream-object.open (“filename”);
Example:
ofstream outfile; //Create stream (for output) outfile.open("DATAl"); // Connect stream to DATAl--------------------------
outfile.close() ; // Disconnect stream from DATA1outfile.open("DATA2”); // Connect stream to DATA2
--------------------------outfile.close() ; // Disconnect stream from DATA2
---------------------------
The above program segment opens two files in sequence for writing the data. Note that the first
file is closed before opening the second one. This is necessary because a stream can be connected
to only one file at a time. See following Program.
// Creating files with open() function
#include <iostream.b> #include <fstream.h>
int main(){
ofstream fout; //create output streamfout.open ("country") // connect "country" to it
fout << "United States of America \n"; fout <<; "United Kingdom \n";fout << "South Korea \n";
fout.close(); //disconnect "country" andfout.open ("capital") ; //connect" capita1 "fout<< "Washi ngton\n";fout <<”london \n"; fout <<"Seoul \n";
fout.close(); // disconnect "capital"
// Reading the files const int N= 80; II size of linechar 1ine [N];
ifstream fin; // create input streamfin.open ("country"); // connect "country" to let
cout <<"contents of country file \n";whi1e (f in)
{ // check end of filefin.getline(line, N); // read a line cout<< line ; //display it}fin.close(); // disconnect "country" andfin.open("capital "); // connect "capital"cout « "\nContents of capital file \n";while{fin) {fin.getline(line, N); cout << 1ine ;}fin.close();return 0;}
The output of Program would be:
Contents of country file United States of AmericaUnited KingdomSouth Korea
Contents of capital file WashingtonLondonSeoul
Disk connect 1 file to fout fout
fin
Connect 1 file to fin
Fig. Streams working on multiple files
At times we may require to use two or more files simultaneously. For example, we may require to
merge two sorted files into a third sorted file. This means, both the sortedfilesha1!1 to be kept open
for reading and the third one kept open for writing. In such cases, we need create two separate input
streams for handling the two input files and one output stream for handling the output file.
// Reads the files created in Program
#include <iostream.h> #include <fstream.h>#include <stdlib.h> / / for exit() function
int main(){const int SIZE = 80; char line[SIZE];ifstream fin1, fin2; create two input streamsfin1.open(“country") ; fin2.open(”capital");for(int i=l; i<=10; i++){if(fin1.eof() ! = 0){cout <<”Exit from country \n";exit(1);}fin1.getline(line.SIZE);cout<< "Capital of "<<line;if(fin2.eof() != 0)
Country file
Capital file
program
program
{cout<< "Exit from capital\n";exit (1) ;}
fin2.getline(line, SIZE); cout << 1ine << "\n";.}return 0;
The output of Program would be:Capital of United States of America WashingtonCapital of United KingdomLondonCapita] of South KoreaSeou1
1.4 DETECTING END-OF FILE
Detection of the end-of-file condition is necessary for preventing any further attempt to read data
from the file. This was illustrated in Program by using the statement
while(fi n)
An ifstream object, such as fin, returns a value of 0 if any error occurs in the file operation including
the end-of-file condition. Thus, the while loop terminates when fin returns a valuezero on reaching
the end-of-file condition. Remember, this loop may terminate due to other failures as well. (We will
discuss other error conditions later.)
There is another approach to detect the end-of-file condition. Note that we have used the
following statement in above Program
if(fin1.eof() ! = 0) {exit(l);}
eof() is a member function of ios class. It returns a non-zero value if the end-of-file (EOF) condition is encountered, and a zero, otherwise. Therefore, the above statement terminates the program on reaching the end of the file.
Summary.
The C++ I/O system contains classes such as ifstream, ofstream and fstream todeal with file
handling. These classes are derived from fstreambase class and aredeclared in a header file
iostream.
A file can be opened in two. ways by using the constructor function of the class andusing the
member function open() of the class.
While opening the file using constructor, we need to pass the desired filename as a parameter
to the constructor.
The openO function can be used to open multiple files that use the same stream object. The
second argument of the openO function called file mode, specifies the purpose for which the
file is opened.
If we do not specify the second argument of the openO function, the default values specified
in the prototype of these class member functions are used while opening the file.
Questions
1 What are input and output streams?
2 What are the steps involved in using a file in a C++ program?
3 Describe the various classes available for file operations?
4 What is the difference between opening a file with a constructor function and opening
a file with openO function? When is one method preferred over the other?
UNIT ILesson 25
Working with files II
Objective
File modes file pointers sequential access file Random access file
MORE ABOUT OPEN(): FILE MODES
We have used ifstream and of stream constructors and the function open() to create new files as well
as to open the existing files. Remember, in both these methods, we used only one argument that was
the filename. However, these functions can take two arguments, the second one for specifying the
file mode. The general form of the function open() with two arguments is:
stream-object.open("filename", mode);
The second argument mode (called file mode parameter) specifies the purpose for which file is
opened. How did we then open the files without providing the second argument in the previous
examples?
The prototype of these class member functions contain default values for the second argument and
therefore they use the default values in the absence of the actual values. The default valuel are as
follows:
ios::in for ifstream functions meaning open for reading only.
ios::out for ofstream functions meaning open for writing only.
The file mode parameter can take one (or more) of such constants defined in the class ios.
lists the file mode parameters and their meanings.
Table File mode parameters
Parameter Meaning
ios::app Append data to the end of the output file.
ios::ate Go to the end of the file when opened.
ios::in Open for reading only
ios::out Open file for output
ios::binary Binary file (if not present, the file is opened as an ASCII file). See the later section "Binary I/O" for a definition of a binary file.
ios::trunc Delete contents of existing file when opening for write.
ios::nocreate Fail if the file does not exist. (Output files only. Opening an input file always fails if there is no file.)
ios::noreplace Open files if the file already exists
1. Opening a file in ios::out mode also opens it in the ios::trunc mode by default.
2. Both ios:app and ios::ate take us to the end of the file when it is opened, The difference
between the two parameters is that the ios::app allows us to add data to the end of the file
only, while ios::ate mode permits us to add data or to modify the existing data anywhere in
the file. In both the cases, a file is created by the specified name, if it does not exist.
3. The parameter ios::app can be used only with the files capable of output.
4. Creating a stream using ifstream implies input and creating a stream using ofstream implies
output. So in these cases it is not necessary to provide the mode parameters.
5. The fstream class does not provide a mode by default and therefore, we must provide the
mode explicitly when using an object of fstream class.
6. The mode can combine two or more parameters using the bitwise OR operator (symbol I )
shown as follows:
fout.open("data", ios::app | ios:: nocreate)
This opens the file in the append mode but fails to open the file if it does not exist.
FILE POINTERS AND THEIR MANIPULATIONS
Each file has two associated pointers known as the file pointers. One of them is called the
input pointer (or get pointer) and the other is called the output pointer (or put pointer). We can use
pointers to move through the files while reading or writing. The input pointer is used for reading the
contents of a given file location and the output pointer is used for writing to a given location. Each
time an input or output operation takes place, the appropriate pointer is
automatically advanced.
Default Actions
When we open a file in read-only mode, the input pointer is automatically set at the beginning So
that we can read the file from the start. Similarly, when we open a file in write-only mode, the
existing contents are deleted and the output pointer is set at the beginning. This enables us to it write
to the file from the start. In case, we want to open an existing file to add more data, the file is opened
in 'append' mode. This moves the output pointer to the end of the file (i.e. the end of the existing
contents).
"hello" file
Open for reading only
input pointer
Open in append mode (for writing more data)
output pointer
Open for writing only
output pointer
Action on file pointers while opening a file
Functions for Manipulation of File Pointers
All the actions on the file pointers as shown in Fig. take place automatically by default. How do we
then move a file pointer to any other desired position inside the file? This is possible only if we can
take control of the movement of. the file pointers ourselves. The file stream classes support the
following functions to manage such situations:
seekg() Moves get pointer (input) to a specified location.
seekp() Moves put pointer(output) to a specified location.
H E L L O W O R L D
H E L L O W O R L D
tellg() Gives the current position of the get pointer.
Tellp() Gives the current position of the put pointer.
For example, the statement
infile.seekg (10 );
moves the file pointer to the byte number 10. Remember, the bytes in a file are numbered beginning
from zero. Therefore, the pointer will be pointing to the 11th byte in the file.
Consider the following statements:
ofstream fileout; fileout.open("hello", ios::app); int p = fileout.tellp();
On execution of these statements, the output pointer is moved to the end of the file "hello" an! the
value of p will represent the number of bytes in the file.
Specifying the offset
We have just now seen how to move a file pointer to a desired location using the 'seek' functions.
The argument to these functions represents the absolute position in the file. This is shown Fig file
file pointer
start end
outfile.seekp(m);
m-bytesFile pointer
'Seek' functions seekg() and seekp() can also be used with two arguments as follows:
seekg (offset, ref position); seekp (offset, refposition);
The parameter offset; represents the number of bytes the file pointer is to be moved from the
location specitied by the-parameter refposition.. The refposition takes one of the following three
constants defined in the ios class:
ios::beg start of the file ios::cur current position of the pointer ios::end end of the file
The seekg() function moves the associated file's 'get' pointer while the seekp() functionmoves the associated file's 'put' pointer.
SEQUENTIAL INPUT AND OUTPUT OPERATIONS
File stream classes support a number of member functions for performing the input and output
operations on files. One pair of functions, put() and get(), are designed for handling a single
character at a time. Another pair of functions, write() and read(), are designed to write and read
blocks of binary data.
Put() and get() Functions
Tbe function put() writes a single character to the associated stream. Similarly, the function getO
reads a single character from the associated stream. Program below illustrates how these fnctions
work on a file. The program requests for a string. On reeiving the string, the program writes it,
character by character, to the file using the put() function in a for loop. Note that the length of the
string i& used to terminate the for loop.
The program then displays the contents of the file on the screen. It uses the function get() to fetch a
character from the file and continues to do so until the end-of-file condition is reached. The character
read from the file is displayed on the screen using the operator <<.
#include <iostream.h> #i nclude <fstream.h> #i nclude <string.h>
int main()
{char string[80];cout<<« n Enter a string \n ";cin>>string;
int len = strlen(string);fstream file; // input and output streamfile.open(“TEXT", ios::in | ios::out);for(int i=0; i<len; i++)
fi1e.put(string [i]); // put a character to file
file.seekg(0); // go to the startchar ch; while(file)
{file.get(ch) ; // get a character from filecout << ch; //display it ()n screen}
return 0;}
The output of Program would be
Enter a string
Cobol_Programming inputCobol_Programming output
We have useid an fstream objectto open the file. Since an fstream object can handle both the input
and output simultaneously, we have opened the file in ios::in | ios::out mode. After writing the file,
we want to read the entire file and display its content. Since the file pointer has already moved to
the end of the file, we must bring it back to the start of the file. This is done by the statement
file.seekg(0);
Write() and read() Functions for Binary files
The functions write() and read(), unlike the functions put() and get(), handle the data in binary form.
This means 'that the values are stored in the disk file in the same format in which they are stored in
the internal memory.
The binary format is more accurate fro storing the numbers as they are stored in the exact internal
representation. There are no conversions while saving the data and therefore saving is much faster.
The binary input and output functions takes the following form:
infile. read ((char *) & V, sizeof (V));outfile.write ((char *) & V, sizeof (V));
These functions take two arguments. The first is the address of the variable V, and the second is the
length of that variable in bytes. The address of the variable must be cast to type char' (i.e. pointer to
character type). Program 11.5 illustrates how these two functions are used to save an array of float
numbers and then recover them for display on the screen.
Prog.: I/O operation on Binary Files
# include<iostream.h># include<fstream.h># include<iomainp.h>
const char * filename = "BINARY";
int main(){float height[4] = {175.5,153.0, 167.25, 160.70};ofstream outfile; outfile.open(filename);outfile.write ((char *) & height, sizeof(height));outfile.close();
for(int i;=0; i<4; i++) / / clear array from memoryheight[i] = 0;outfile.close();ifstream infile;infile.open (fi1ename) ;infile.read((char *) & height. sizeof(height));for(i=0;i<4;i++) {cout.setf (ios::showpoint);cout<< setw(10) << setprecision(2)
<< height[i];}return 0;
The output of Program
175.50 153.00 167.25
Reading and Writing a Class Object
We mentioned earlier that one of the shortcomings of the I/O system of C is that it cannot handle
user-defined data types such as class objects. Since the class objects are the central element C++
programming, it is quite natural that the language supports features for writing to a reading from
the disk files objects directly. The binary input and output functions read() and write() are designed
to do exactly this job. These functions handle the entire structure of object as a single unit, using the
computer's internal representation of data. For instance, function write() copies a class object from
memory byte by byte with no conversion. one important point to remember is that only data members
are written to the disk me and member functions are not.
Program illustrates how class objects can be written to and read from the disk file!. The length of the
object is obtained using the sizeof operator. This length represents them total of lengths of all data
members of the object.
#include <iostream.h> #include <fstream.h>#include <iomainp.h>
class INVENTORY {
char name,[10]; // item nameint code; // item code
float cost; / / cost of each itempublic:void readdata(void);void writedata(void);
};void INVENTORY:: readdata(void){//read from keyboardcout << "Enter name: ;cin >> name; cout << " Enter code:”; cin >> code; cout <<"Enter cost:”; cin>> cost;}void INVENTORY:: writedata (void) / / formatted{ / / screencout << setiosflags(ios::left)<< setw(10) << name.<< setiosflags(ios: :right)<< setw(10)<< code<< setprecision(2}<< setw(lO) <<<< endl;
}int main () {INVENTORY item[3];fstream fi1e;file.open (“STOCK.DAT” , ios::in | ios::out);cout << “ENTER DETAILS FOR THREE ITEMS \n” ;for(int i =0; i <3; i ++){item[i].readdata();file.write((char*) & item[i] .sizeof(item[i]));}file. seekg (0);cout << “\nOUTPUT\n\n”; for(i= 0; i < 3;I++) {
file. read [(char *) & item[ih sizeof(i tem[i]»; i tem[i] .writedata 0;return 0;}
The output of Program
ENTER DETAILS FOR THREE ITEMS
Enter name: C++ Enter code: 101 Enter cost: 175Enter name: FORTRAN Enter code: 102 Enter cost: 150 Enter name: JAVA Enter code: 115 Enter cost: 225
OUTPUT
C++ 101 175 FORTRAN 102 150JAVA 115 225
The program uses 'for' loop for reading and writing objects. This is possible because we Know the
exact number of objects in the file. In case, the length of the file is not known, we can determine the
file-size in terms of objects with the help of the file pointer functions and use it in the 'for' loop or we
may use while (file) test approach to decide the end of the file. These techniques are discussed in the
next section.
UPDATING A FILE: RANDOM ACCESS
Updating is a routine task in the maintenance of any data file. The updating would include one or
more of the following tasks:
Displaying the contents of a file.
Modifying an existing item.
Adding a new item.
Deleting an existing item.
These actions require the file pointers to move to a particular location that corresponds to the
item/object under consideration. This can be easily implemented if the file contains a collection of
items/objects of equal lengths. In such cases, the size of each object can be obtained using the
statement
int object_length = sizeof(object);
Then, the location of a desired object, say the mth object, may be obtained as follows:
int location = m * object_length;
The location gives the byte number of the first byte of the mth object. Now, we can set the file
pointer to reach this byte with the help of seekg() or seekp().
We can also find out the total number of objects in a file using the object_length as follows:
int n = file_size/object_length;
Tbe file_size can be obtained using the function tellgO or tellpO when the file pointer is located at
the end of the file.
Program illustrates how some of the tasks described above are carried out. The program uses the
"STOCKDAT" file created using Program for five items and performs following operations on the
file:
1. Adds a new item to the file.3. Modifies the details of an item. 4. 3, Displays the contents of the file
#include <iostream. h>#include <fstream.h> #inc1ude <iomanip. h>c1ass INVENTORY {char name[l0] ; int code;float cost;
public:
void getdata(void) {cout << "Enter name: “; ci n >> name ; cout << Enter code:”; cin >> code;cout<<"Enter cost :”;cin >> cost;}void putdata (void) {cout << setw(10) << name << setw(l0) << code
<< setprecision(2)<< setw(10) << cost << endl;}}; // End of class definition
int main() {INVENTORY item; fstream inoutfile;
inoutfile.open("STOCK.DAT", ios:: ate | ios:: in |ios::out | ios::binary);inputfile.seekg(0,ios:: beg) ; // go to start
cout << "CURRENT CONTENTS OF STOCK" << "\n";while(inoutfile.read((char *) & item, sizeof item)){item.putdataO;} inoutfi1e.c1ear(); // turn of EOF flag
/* »»»»»»> Add one more item ««««««« * /
cout << "\n ADD AN ITEM \n”;item.getdata(); char ch; cin.get(ch);inoutfile.write( (char & item, si zeof item);
/ / Display the appened file
inoutfi1e.seekg(Q). // go to the startcout << "CONTENTS OF APPENDED FILE \n";
while (inoutfile.read((char *) & item , sizeof item)){item.putdata();}
//find number of objects in the fi1e
int last= inoutfile.tellg();int n = last/sizeof(item);cout << "Number of objects = " « n « "\n";
cout <<”Total bytes in the file = ”<<last<<”\n”;
/*<<<<<<<<<<<<MODIFY THE DETAILS OF AN ITEM <<<<<<<<<<< */
cout <<”Enter object number to be updated \n";int object;cin>>object;cin.get(ch);int location=(object-1)*-sizeof(item);
if(inoutfile.eof())inoutfile.clear();
cin.get(ch);I
int location" (object-I) * sizeof(item);if(inout fi1e .eof()) inoutfile.clear() ;
inoutfi1e.seekp(location) ;cout << "Enter new values of object \n"; item.getdata(); cin.get(ch);
inoutfile.write«char *) & item, sizeof item)?<< flush;
/-*»»»»»»> SHOW UPDATED FILE ««««<<<<<<< */
inoutfile.seekg(O); // go to the start
cout << "CONTENTS OF. UPDATED FILE \n”;
while(inoutfile.read((char *) & item sizeof item)){item.putdata() ;}
inoutfile.close();
return 0; } //End of main
The output of Program would be:
CURRENT CONTENTS OF STOCK
AA 11 100 BB 22 200 CC 33 300 DO 44 400 XX 99 900
ADD AN ITEMEnter name: YY Enter code: 10Enter cost: 101
CONTENTS OF APPENDED FI LEAA 11 100BB 22 200CC 33 300DD 44 400XX 55 500YY 66 600
Number of objects = 6Tota1 bytes in the fi1es = 96 Enter object number to be updated 6Enter new values of the object Enter name: ZZEnter code: 20Enter cost: 201
CONTENTS OF UPDATED FI LEAA 11 100 SS 22 200 CC 33 300 DD 44 400 XX 99 900 ZZ 20 201
We are using the fstream class to declare the me streams. The fstream class inherits two buffers, one
for input and another for output, and synchronizes the movement of the file pointers on these buffers.
That is, whenever we read from or write to the file, both the pointers move in tandem. Therefore, at
any point of time, both the pointers point to the same byte.
Since we have to add new objects to the file as well as modify some of the existing objects, we open
the file using ios::ate option for input and output operations. Remember, the option ios::app allows
us to add data to the end of the file only. The ios::ate mode sets the file pointers at the end of the file
when opening it. We must therefore move the 'get' pointer to the.beginning of the file using the
function seekg() to read the existing contents of the file.
At the end of reading the current contents of the file, the program sets the EOF flag on. This prevents
any further reading from or writing to the file. The EOF flag is turned off by using the function
clear(), which allows access to the file once again.
After appending a new item, the program displays the contents of the appended file and
also the total number of objects in the file and the memory space occupied by them.
To modify an object we should reach to the first byte of that object. This is achieved using
the statements .
int location = (object-1) * sizeof(item};
inoutfile.seekp(location};
The program accepts the number and the new values of the object to be modified and updates it
finally , the contents of the appended and modified file are displayed.
Remember , we are opening an existing file for reading and updating the values. It is, therefore,
essential that the data members are of the same type and declared in the same order as in the , file.
Since, the member functions are hot stored, they can be different.
Summary
When a file is opened for writing only, a new file is created only if there is no file of that
name. If a file by that name already exists, then its contents are deleted and the file is
presented as a clean file.
To open an existing file for updating without losing its original contents, we need to open it
in an append mode.
The fstream class does not provide a mode by default and therefore we must provide the
mode explicitly when using an object off stream class. We can specify more than one file
modes using bitwise OR operator while opening a file.
Each file has associated two file pointers, one is called input or get pointer, while the other is
called output or put pointer. These pointers can be moved along the files by member
functions.
putO and getO functions handle single character at a time. writeO and readO functions write
and read blocks of binary data
.
Questions
1 .What is a file mode? Describe the various file mode options available.
2 Write a statement that will create an object called fob/or writing, and associate it with a file name
DATA.
How many file objects would you need to create to manage the following situations?
(a) To process four files sequentially.
(b) To merge two sorted files into a third file.
Explain.
Both ios::ate and ios::app place the file pointer at the end of the file (when it is opened). What then,
is the difference between them?
UNIT I
Lesson 26
Working with file III
Objectives
Error handling Command line arguments
ERROR HANDLING DURING FILE OPERATIONS
So far we have been opening and using the files for reading and writing on the assumption that
everything is fine with the files. This may not be true always. For instance, one of the Following
things may happen when dealing with the files:
1. A file which we are attempting to open for reading does not exist.
2, The file name used for a new file may already exist.
3, We may attempt an invalid operation such as reading past the end-of-file.
4. There may not be any space in the disk for storing more data.
5. We may use an invalid file name.
6. We may attempt to perform an operation when the file is not opened for that purpose.
The c++ file stream inherits a 'stream-state' member from the class ios. This member records
information on the status of a file that is being currently used. The stream state member uses bit
fields to store the status of the error conditions stated above.
The class ios supports several member functions that can be used to read the status ! recorded in a
file stream. These functions along with their meanings are listed in Table
Table
Error handling functionsfunction Return value and meaning
Returns true (non-zero value) if end-of-file is encounteredeofOwhile reading;Otherwise returns false(zero)
Fail() Returns true when an input or output operation has failed
BadO Returns true if an invalid operation is attempted or anyUnrecoverable error has occurred. However, if it is false, itMay be possible to recover from any other error reported,And continue operation.
goodO Returns true if no error has occurred. This means, all theAbove functions are false. For instance, if file.goodO isTrue, all is well with the stream file and we can ,proceed toPerform I/O operations. When it returns false, no furtherOperations can be carried out. .
These functions may be used in the appropriate places in a program to locate the status of a file stream and thereby to take the necessary corrective measures. Example:
ifstream infile; infile.open("ABC"); while(!infile.fail ()){…………(process the fi 1 e)……..…..
}i f(infi1e.eof()){(terminate program normally)
}
elseif(infile.bad()){}else{ infile.clear() ;
……… (report fatal error) // clear error state……..
}…..………
The function clear() (which we used in the previous section as well) resets the error stateSil that further operations can be attempted.Remember that we have already used statements such aswhile(infile) {
…….……..}andwhile(infile.read(……))
{…….……
Here, infile becomes false (zero) when end of the file is reached ( and eofO becomes true).
COMMAND-LINE ARGUMENTS
Like C, C++ too supports a feature that facilitates the supply of arguments to the main() function.
These arguments are supplied at the time of invoking the program. They are typically used to pass
the names of data files. Example:
C > exam data results
Here, exam is the name of the file containing the program to be executed, and data and results are the
filenames passed to the program as command-line arguments.
The command-line arguments are typed by the user and are delimited by a space. The first argument
is always the filename (command name) and contains the program to be executed. How do these
arguments get into the program?
The main() functions which we have been using up to now without any arguments can take two
arguments as shown below:
main(int argc, char * argv[])
The first argument argc (known as argument counter) represents the number of arguments in the
command line. The second argument argv (known as argument vector) is an array of char type
pointers that points to the command line arguments. The size of this
array will be equal to the value of argc. For instance, for the command line.
C > exam data results
the value of argc would be 3 and the argv would be an array of three pointers to strings as shown below:argu [0]_> exam argu [1] n_> dataargu[2] ---> results
Note that argv[0] always represents the command name that invokes the program. The character pointers argv[l] and argv[2] can be used as file names in the file opening statements as shown below:
……..……..infile.open(argv[l]); // open data fi 1 e for reading
outfile.open(argv[2]); // open results file for writing
Program illustrates the use of the command-line arguments for supplying theThe command line is
Test ODD EVEN
The program creates two files called ODD and EVEN using the command-line arguments and a set
of numbers stored in an array are written to these files. Note that the odd numbers are written to the
file ODD and the even numbers are written to the file EVEN. The then displays the contents of the
files.
#include <iostream.h> #include <fstream.h> #include <stdlib.h>
main(int argc, char * argv[]){int number [9] = {1l.22.33.44.55!66.77 .88.99};It(argc != 3){
cout<<”argc=”<<argc<<”\n”;cout <<”Error in arguments \n”;exit(1);}
ofstream foutl. fout2;
fout1.open(argv[1]);if(fout1.fail()){
cout << could not open. the file”<< argv[2] <<” \n”;
exit(1);}for ( int i=0; i<9;i++){if(number[ i ] % 2 == 0) fout2 « number[i] « “ "; // write to. EVEN file
e1sefout 1<< number[i]<<” ”; // write to ODD file
}fout1.close();fout2.close();
ifstream. fin;
char ch;
for(i=1; i<argc; i++){fin.open(argv[i]);
cout « "Contents of “<< argv[i] << “\n”;
do .{fin.get(ch); / / read a valuecout << ch; / / display it}while(fin); cout << ''\n\n”;fin.close();} return 0;}
The output of Program would be:
Cantents af ODD 11 33 55 77 99
Cantents af EVEN 22 44 66 88
Summary
. The class ios supports many member functions for managing errors that may occur during
file operations.
File names may be supplied as arguments to the main() function at the time of invoking the
program. These arguments are known as command-line arguments.
.
Questions
1. What does the "current position" mean when applied to files?
2. Write statements using seekg() to achieve the following:
(a) To move the pointer by 15 positions backward from current position.
(b) To go to the beginning after an operation is over.
(c). To go backward by 20 bytes from the end.
(d) To go to byte number 50 in the file.
UNIT I
LESSON 27
TEMPLATE I
Objective
Need of Template
Class template
Templates
INTRODUCTION (Need of Template)
Templates is one of the features added to C++ . It is a new concept which enable us define generic
classes and functions and thus provides support for generic programming. Generic programming is
an approach where generic types are used as parameters in algorithms so that they work for a variety
of suitable data types and data structures. Support for generic programming in C++ is considered by
some to be as important a language goal for C++ as is support for object-oriented programming
(using base/derived classes and virtual functions).
Templates are a powerful but complex feature, about which we will have more to say. Languages
like C or Java(tm), that do not have templates, typically use macros or rely on using base class
pointers and virtual functions to synthesize some of the properties of templates.
A template can be used to create a family of classes or functions. For example, a class template for
an array class would enable us to create arrays of various data types such as int
Array and float array. Similarly, we can define a template for a function, say mul( ), that would help
us create various versions of mul( ) for multiplying, int, float and double types.
A template can be considered as a kind of macro. When an object of a specific type is led for actual
use, the template definition for that class is substituted with the required type. Since a template is
defined with a parameter that would be replaced by a specified type at the time of actual use of the
class or function, the templates are sometimes called parameterized classes or functions.
CLASS TEMPLATES
Consider a vector class defined as follows:
class vector
{
int *v;
int size;
public:
vector(int m) / /, create a null vector
{
v = new int[size = m];
for(int i=0; i<size; i++)
v[i] = 0;
}
vector(int *a) / / create a vector from an array
{
for(int i=O; i<size; i++)
v[i] = a[i];
}
int operator*(vector &y) / / scalar product
{
int sum = 0;
for(int i=0; i<size; i++)
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 vectors as
shown below:
int main( )
{
int x[3] = {1,2,3};
int y[3] = {4,5,6};
vector v1(3); / / Creates a nuII vector of 3 integers
vector v2(3);
v1= x; / / Creates v 1 from the array x
v2= y;
int R = v1 * v2;
cout<< “R = “ R;
return 0;
}
Now suppose we want to define a vector that can store an array of float values. We can do this by
simply replacing the appropriate int declarations with float in the vector class. This means that we
have to redefine the entire class all over again.
Assume that we want to 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. The template
mechanism enables us to achieve this goal.
As mentioned earlier, templates allow us to define generic classes. It is a simple process to create a
generic class using a template with an anonymous type. The general format of a class template is:
template<class T>
class classname
{
// .........
// class member specification
// with anonymous type T
// wherever appropriate
// .........
);
The template definition of vector class shown below illustrates the syntax of a template:
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 += this -> v[i] * Y - v[i];
return sum;
}
};
Remember:
Class template definition is very similar to an ordinary class definition except. prefix
template<class T> and the use of type T. This prefix tells the compiler Iii we are going to declare a
template and use T as a type name in the declaration, Thus vector has become a parameterized class
with the type T as its parameter, T may be substituted by any data type including the user-defined
types. Now, we can create vectors for holding different data types.
Example:
vector <int> v1(10); // 10 element int vector
vector <float> v2 (25) ; // 25 element float vector
Remember:
The type T may represent a class name as well.
Example:
vector <complex> v3(5); // vector of 5 complex numbers
A class created from a class template is called a template class. The syntax for defining, object of a
template class is:
classname<type> objectname (arglist) ;
This process of creating a specific class from a class template is called instantiation, compiler will
perform the error analysis only when an instantiation takes place. So it is, advisable to create and
debug an ordinary class before converting it into a template.
Following Programs illustrate the use of a vector class template for performig scalar product of int
type vectors as well as float type vectors.
#include <iostream>
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 + = 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;
vl = X;
v2 = Y;
int R = v1 * v2;
cout <<” R = “ << R << “\n”;
return 0;
}
Output R= 32
Here is another example of class template
While implementing class template member functions, the definitions are prefixed by the keyword
template. Here is the complete implementation of class template Stack:
//stack.h
#pragma once
template <class T>
class Stack
{
public:
Stack(int = 10) ;
~Stack( ) { delete [] stackPtr ; }
int push(const T&);
int pop(T&) ; // pop an element off the stack
int isEmpty( )const { return top == -1 ; }
int isFull( ) const { return top == size - 1 ; }
private:
int size ; // Number of elements on Stack
int top ;
T* stackPtr ;
} ;
//constructor with the default size 10
template <class T>
Stack<T>::Stack(int s)
{
size = s > 0 && s < 1000 ? s : 10 ;
top = -1 ; // initialize stack
stackPtr = new T[size] ;
}
// push an element onto the Stack
template <class T>
int Stack<T>::push(const T& item)
{
if (!isFull( ))
{
stackPtr[++top] = item ;
return 1 ; // push successful
}
return 0 ; // push unsuccessful
}
// pop an element off the Stack
template <class T>
int Stack<T>::pop(T& popValue)
{
if (!isEmpty( ))
{
popValue = stackPtr[top--] ;
return 1 ; // pop successful
}
return 0 ; // pop unsuccessful
}
Using a class template
Using a class template is easy. Create the required classes by plugging in the actual type for the type
parameters. This process is commonly known as "Instantiating a class".
Here is a sample driver class that uses the Stack class template.
#include <iostream>
#include "stack.h"
using namespace std ;
void main( )
{
typedef Stack<float> FloatStack ;
typedef Stack<int> IntStack ;
FloatStack fs(5) ;
float f = 1.1 ;
cout << "Pushing elements onto fs" << endl ;
while (fs.push(f))
{
cout << f << ' ' ;
f += 1.1 ;
}
cout << endl << "Stack Full." << endl
<< endl << "Popping elements from fs" << endl ;
while (fs.pop(f))
cout << f << ' ' ;
cout << endl << "Stack Empty" << endl ;
cout << endl ;
IntStack is ;
int i = 1.1 ;
cout << "Pushing elements onto is" << endl ;
while (is.push(i))
{
cout << i << ' ' ;
i += 1 ;
}
cout << endl << "Stack Full" << endl
<< endl << "Popping elements from is" << endl ;
while (is.pop(i))
cout << i << ' ' ;
cout << endl << "Stack Empty" << endl ;
}
Program Output
Pushing elements onto fs
1.1 2.2 3.3 4.4 5.5
Stack Full.
Popping elements from fs
5.5 4.4 3.3 2.2 1.1
Stack Empty
Pushing elements onto is
1 2 3 4 5 6 7 8 9 10
Stack Full
Popping elements from is
10 9 8 7 6 5 4 3 2 1
Stack Empty
Summary
Templates is one of the features added to C++ . It is a new concept which enable us define
generic classes and functions and thus provides support for generic programming.
Generic programming is an approach where generic types are used as parameters in
algorithms so that they work for a variety of suitable data types and data structures.
Templates are a powerful but complex feature
A template can be used to create a family of classes or functions.
This process of creating a specific class from a class template is called instantiation.
While implementing class template member functions, the definitions are prefixed by the
keyword template.
Question
What is Template? Define Class template with suitable example?
Define class template? Give an example of class stack template?
UNIT I
LESSON 28
TEMPLATE II
Objective
Function template
Implementing function template
Template Instantiation
FUNCTION TEMPLATES
Like class templates, we can also define function templates that could be used to create family of
functions with different argument types.
To perform identical operations for each type of data compactly and conveniently, use function
templates. You can write a single function template definition. Based on the argument types
provided in calls to the function, the compiler automatically instantiates separate object code
functions to handle each type of call appropriately. The STL algorithms are implemented as function
templates.
The general format of a function template is:
template<class T>
returntype functioname (arguments of type T)
{
// .....
// Body of function
// with type T
// wherever appropriate
// .....
}
The function template syntax is similar to that of the class template except that we are defining
functions instead of classes. We must use the template parameter T as and when necessary in the
function body and in its argument list.
Implementing Template Functions
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 ;
}
Following example declares a swap( ) function template that will swap two values of given type of
data.
template<class T>
void swap (T&x, T&y)
{
T temp = X;
X = Y;
Y = temp;
}
This declares a set of overloaded functions, one for each type of data, We can invoke the Swap( )
function like any ordinary function. For example, we can apply the swap Function as follows:
void f(int m, int n, float a, float b)
{
swap(m,n); // swap two integer values.
swap(a,b); // swap two float values
//………..
}
This will generate a swap() function from the function template for each set of argument types.
Following shows how a template function is defined and implemented.
Example Function Template
# <inc1ude<iostream>
using namespace std;
template <class T>
Void swap(T &x. T &y)
{
T temp = x;
x =y;
y = temp;
}
void fun (int m. int n, float a, float b)
{
cout <<” m and n before swap: " << m << " “ << n<<”\n”;
swap(m.n);
cout <<” m and n after swap:" << m << " " << n << "\n";
cout « "a and b before swap:" << a << " " << b << "\n";
swap(a.b);
cout « "a and b after swap:" << a << “ " << b << "\n";
}
int main( )
{
fun(l00,200,l1.22,33.44) ;
return 0;
}
The output of Program
m and n before swap: 100 200
m and n after swap: 100 200
a and b before swap: 11.22 33.439999
a and b after swap: 33.439999 11.22
Another function often used is sort() for sorting arrays of various types such as int and
double. The following example shows a function template for bubble sort
template<class T>
bubble(T a[], int n)
{
for(int i=0; i<n-l; i++)
for(int j=n-l; i<j; j--)
if(a[j] < a[j-l])
{
T temp = v[j];
v [j] = v [j -1] ;
v[j-l] = temp;
}
}
Note that the swapping statements
T temp = v[j];
v[j] = v[j-l];
v[j-l] = temp;
may be replaced by the statement
swap(v[j],v[j-l]);
where swap() has been defined as a function template.
Ex.] Program returns the maximum of the two elements using template function.
#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 ;
}
void 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 ;
}
Program Output
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
Template Instantiation
When the compiler generates a class, function or static data members from a template, it is referred
to as template instantiation.
A class generated from a class template is called a generated class.
A function generated from a function template is called a generated function.
A static data member generated from a static data member template is called a generated
static data member.
The compiler generates a class, function or static data members from a template
when it sees an implicit instantiation or an explicit instantiation of the
template.
This is an example of implicit instantiation of a class template.
template <class T>
class Z
{
public:
Z( ) {} ;
~Z( ) {} ;
void f( ){} ;
void g( ){} ;
} ;
int main( )
{
Z<int> zi ; //implicit instantiation generates class Z<int>
Z<float> zf ; //implicit instantiation generates class Z<float>
return 0 ;
}
Summary
Function templates are implemented like regular functions, except they are prefixed with the
keyword template
When the compiler generates a class, function or static data members from a template, it is
referred to as template instantiation.
A function generated from a function template is called a generated function
Question
What is Template? Define Function template with suitable example?
Show how template function is define & implemented ?
UNIT I
LESSON 29
TEMPLATE III
Objective
Class with multiple arguments
Function with multiple arguments
Overloading Of Template Functions
MULTIPLE ARGUMENTS :
CLASS TEMPLATES WITH MULTIPLE PARAMETERS
We can use more than one generic data type in a class template. They are declared as a comma
separated list within the template specification as shown below:
template<class T1, class T2, ...>
class classname
{
……….(Body of the class)
……….
……….
};
Following program demonstrates the use of a template class with two generic data types.
# include<iostream>
using namespace std;
template <class T1 , class T2>
class test
{
Tl a;
T2 b;
publ ic:
Test(Tl x, T2 y)
{
a = x;
b = y;
}
void show()
{
cout « a « “and “ «b « "\n";
}
};
int main()
{
Test <.float , int> test (1.23,123);
Test <int, char> test2 (l00,'W');
test1.show();
test2.show() ;
return 0;
};
The output will be:
1.23 and 123
100 and W
FUNCTION TEMPLATES WITH MULTIPLE PARAMETERS
Like template classes, we can use more than one generic data type in the template statement, using a
comma-separated list as shown below:
template<class T1, class T2, ...>
return type functi onname (arguments of types T1, T2,…)
{
……………(Body of function)
…………….
……………
}
Program illustrates the concept of using two generic types in template functions.
#<include <iostream>
#<include <string>
using namespace std;
template<class T1, class T2>
void display(T1 x, T2 y)
{
cout « X « “ “ « y « “\n”;
}
int main()
{
display(1999, EBG);
display(12.34. 1234);
return 0;
}
The output of Program would be:
1999 EBG
12.34 1234
C++ templates allow one to implement a generic Queue<T> template that has a type parameter T. T
can be replaced with actual types, for example, Queue<Customers>, and C++ will generate the class
Queue<Customers>. For example,
template <class T>
class Stack
{
} ;
Here T is a template parameter, also referred to as type-parameter.
1. C++ allows you to specify a default template parameter, so the definition could now look
like:
2. template <class T = float, int elements = 100> Stack { ....} ;
Then a declaration such as
Stack<> mostRecentSalesFigures ;
would instantiate (at compile time) a 100 element Stack template class named
mostRecentSalesFigures of float values; this template class would be of type Stack<float, 100>.
Note, C++ also allows non-type template parameters. In this case, template class Stack has an int as
a non-type parameter.
If you specify a default template parameter for any formal parameter, the rules are the same
as for functions and default parameters. Once a default parameter is declared all subsequent
parameters must have defaults.
Default arguments cannot be specified in a declaration or a definition of a specialization. For
example,
template <class T, int size>
class Stack
{
} ;
OVERLOADING OF TEMPLATE FUNCTIONS
A template function may be overloaded either by template functions or ordinary function of its
name. In such cases, the overloading resolution is accomplished as follows:
1. Call an ordinary function that has an exact match.
2. Call a template function that could be created with an exact match.
3. Try normal overloading resolution to ordinary functions and call the one that ma'
An error is generated if no match is found. Note that no automatic conversions are applied to
arguments to the template functions.
Following Program shows how a template function overloaded with an explicit function.
#include<iostream>
#include<string>
using namespace std;
template < class T>
void display (T x)
{
cout <<”Template display :”<<x<<”\n”;
}
void display (int x) //overloads the generic display( )
{
cout <<”Explicit display : ”<<x<<”\n”;
}
int main( )
{
display(100);
display(12.34);
display(‘C’);
return 0;
}
The output will be
Explicit display : 100
Template display :12.34
Template display:C
Remember: The call display (100) invokes the ordinary version of display() and not the template
version.
Summary
They are declared as a comma separated list within the template specification
Like template classes, we can use more than one generic data type in the template statement,
using a comma-separated list
C++ templates allow one to implement a generic Queue<T> template that has a type parameter T
T can be replaced with actual types, for example, Queue<Customers>
If you specify a default template parameter for any formal parameter, the rules are the same as
for functions and default parameters.
A template function may be overloaded either by template functions or ordinary function of its
name
Question
Explain class template & function template with multiple arguments?
Shows how a template function can be overloaded with an explicit function.
UNIT I
LESSON 30
EXCEPTION HANDLING
Objective
What is exception handling? Exception Handling Mechanism. Throw Mechanism.
INTRODUCTION
We know that it is very rare that a program works correctly first time. It might have bu~, The two
most 'Common types of bugs are logic errors and syntactic errors. The logic error occur due to poor
understanding of the problem and solution procedure. The syntactic error arise due to poor
understanding of the language itself. We can detect these errors by using exhaustive, debugging and
testing procedures.
We often come across some peculiar problems other than logic or syntax errors. They are
Known as exceptions.. Exceptions are run time anomalies or unusual conditions that a program may
encounter while executing. Anomalies might include conditions such as division by zero,Access to
an array outside of its bounds, or running out of memory or disk space. When a Program encounter
an exceptional condition, it is important that it is identified and dealt effectively. ANSI C++ provides
built-in language features to detect and handle exceptions, which are basically run time errors.
Exception handling was not part of the original C++. It is a new feature added to ANSI C++
Today, almost all compilers support this feature. C++ exception handling provides a type-safe
Integrated approach, for coping with the unusual predictable problems that arise while executing
a program.
BASICS OF EXCEPTION HANDLING
Exceptions are of two kinds, namely, synchronous exceptions and asynchronous exceptions. I
such as "out-of-range index" and "over-flow" belong to the synchronous type exceptions.errors that
are caused by events beyond the control of the program (such as keyboard interrupts) are called
asynchronous exceptions. The proposed exception handling mechanism, in C++ is designed to
handle only synchronous exceptions.
The purpose of the exception handling mechanism is to provide means to detect and report
“exceptional circumstance” so that appropriate action can be taken. The mechanism
Suggest a separate error handling code that performs the following tasks:
1. Find the problem (Hit the exception).
2. Inform that an error has occurred (Throw the exception).
3. Receive the error information (Catch the exception).
4. Take corrective actions (Handle the exception).
The error handling code basically consists of two segments, one to detect errors and to throw
exceptions, and the other to catch the exceptions and to take appropriate actions.
EXCEPTION HANDLING MECHANISM
In C there are several ways to have a program react to situations which break the normal
unhampered flow of the program:
The function may notice the abnormality and issue a message. This is probably the least
disastrous reaction a program may show.
The function in which the abnormality is observed may decide to stop its intended task,
returning an errorcode to its caller. This is a great example of postponing decisions: now the
calling function is faced with a problem. Of course the calling function may act similarly, by
passing the error-code up to its caller.
The function may decide that things are going out of hand, and may call exit() to terminate
the program completely. A tough way to handle a problem.
The function may use a combination of the functions setjmp() and longjmp()) to enforce non-
local exits. This mechanism implements a kind of goto jump, allowing the program to
proceed at an outer section, skipping the intermediate levels which would have to be visited
if a series of returns from nested functions would have been used.
In C++ all the above ways to handle flow-breaking situations are still available. However, the last
way, using setjmp() and longjmp() isn't often seen in C++ (or even in C) programs, due to the fact
that the program flow is completely disrupted.
In C++ the alternative to using setjmp() and longjmp() are exceptions. Exceptions are a mechanism
by which a controlled non-local exit is realized within the context of a C++ program, without the
disadvantages of longjmp() and setjmp().
Exceptions are the proper way to bail out of a situation which cannot be handled easily by a function
itself, but which are not disastrous enough for the program to terminate completely. Also, exceptions
provide a flexible layer of flow control between the short-range return and the crude exit().
C++ exception handling mechanism is basically built upon three keywords, namely, try, throw, and
catch. The keyword try is used to preface a block of statements (surrounded by braces), which may
generate exceptions. This block of statements is known as try block. When an error is detected, it is
thrown using a throw statement in the try block. Throw followed by an expression of a certain type,
throws the expression value as an exception. The throw statement should be executed somewhere
within the try-block: either directly or from within a function called directly or indirectly from the
try-block. A catch block defined by the keyword catch 'catches' the exception 'thrown' by the throw
statement in the try block, and handles it appropriately. The relationship is shown in Fig.
Try block throwing Exception
The catch block that catches an exception must immediately follow the try block that throws the
exception. The general forms of these two blocks are as follows:
try block
Detects and throws an exception
catch block
Catches and handles the exception……………………try { ………..throw exception; / / Block of statements which
/ / detects and throws an exception
}catch (type arg) / / Catches exception{
/ / Block of statements that / / handles the exception
}………………
When the try block throws an exception, the program control leaves the try block and enters the
catch statement of the catch block. Note that exceptions are objects used to transmit information
about a problem. If the type of object thrown matches the arg type the catch statement, then catch
block is executed for handling the exception. If they do not match, the program is aborted with the
help of the abort( )function which is invoked by default. When no exception is detected and thrown,
the control goes to the statement immediately after the catch block. That is, the catch block is
skipped. This simple try-catch mechanism is illustrated in Program.
Try Block Throwing An Exception.
#include <iostream.h>
using namespace std;
int main( )
{
int a,b;
cout<< “enter values of a and b \n”
cin>>a;
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 : x = “ x << “\n”;
}
cout<< “END”;
return 0;
}
The output of Program
First Run
Enter Values of a and b
20 15
Result (a/x) = 4
END
Second Run
Enter Values of a and b
10 10
Except; on caught: x = 0
END
Program detects and catches a division-by-zero problem. The output of first run shows a
successful execution. When no exception is thrown, the catch block is skipped and execution
resumes with the first line after the catch. In the second run, the denominator x becomes zero and
therefore a division-by-zero situation occurs: This exception is thrown using the object x. Since the
exception object is an int type, the catch statement containing int type argument catches the
exception and displays necessary message.
Most often, exceptions are thrown by functions that are invoked from within the try blocks.
The point at which the throw is executed is called the throw point. Once an exception is thrown to
the catch block, control cannot return to the throw point. This kind of relationship js shown in Fig.
Function invoked by try block throwing exception
The general format of code for this kind of relationship is shown below
Throw point
Function that causes an exception
try block
Invokes a function that contains an exception
catch block
Catches and handles the exception
Type function(arg list) // function with exceptin{
……….………throw(object); //throws object……….………
}
……….………
try{……….……… invoke function here……….………}
catch (type arg) //catches exception{……….……… handles exception here……….………} ………….
Remember :
Try block is immediately followed by the catch block, irrespective of the location of the
throw point.
Program demonstrate how a try block invokes a function that generates an exception.
// Invoking function that generates exception.
#include <iostream>
using namespace std;
void divide(int x, int y , int z)
{
cout<< “\n we r inside the function \n”
if((x-y) != 0) // it is ok
{
int R = z / (x-y);
cout<< “ Result = “ << R <<”\n”;
}
else //There is a problem
{
Throw(x-y) //throw point
}
}
int main( )
{
try
{
cout<< “ we r inside the Try block \n”;
divide(10,20,30); //invoke divide( )
divide(10,20,30); //invoke divide( )
}
catch(int i) //catches the exception
{
cout<< “ caught the exception \n”;
}
return 0;
}
Output
We r inside the try Block
We r inside the function
Result = -3
We r inside the function
Caught the exception
THROWING MECHANISM
When an exception that is desired to be handled is detected, it is thrown using the throw statement in
one of the following forms:
throw(exception);
throw except ion;
throw; // used for rethrowing an exception
The operand object exception may be of any type, including constants. It is also possible to
Throw objects not intended for error handling.
When an exception is thrown, the catch statement associated with the try block will catch it. That is,
the control exits the current try block, and is transferred to the catch block after that try block.
Objects defined locally in functions are automatically destroyed once exceptions are thrown within
these functions. However, if the object itself is thrown, the exception catcher receives a copy of the
thrown object. This copy is constructed just before the local object is destroyed.
The next source illustrates this point. Within the function Object::fun() a local Object toThrow is
created, which is thereupon thrown as an exception. The exception is caught outside of Object::fun(),
in main(). At this point the thrown object doesn't actually exist anymore,
Let's first take a look at the sourcetext:
#include <iostream.h>
#include <string>
class Object
{
public:
Object(string name)
name(name)
{
cout << "Object constructor of " << name << "\n";
}
Object(Object const &other)
name(other.name + " (copy)")
{
cout << "Copy constructor for " << name << "\n";
}
~Object()
{
cout << "Object destructor of " << name << "\n";
}
void fun()
{
Object
toThrow("'local object'");
cout << "Object fun() of " << name << "\n";
throw toThrow;
}
void hello()
{
cout << "Hello by " << name << "\n";
}
private:
string
name;
};
int main()
{
Object
out("'main object'");
try
{
out.fun();
}
catch (Object o)
{
cout << "Caught exception\n";
o.hello();
}
}
The class Object defines some simple constructors and members. The copy constructor is special in
that it adds the text " (copy)" to the received name, to allow us to monitor the construction and
destruction of objects somewhat more closely. The member function fun() generates the exception,
and throws its locally defined object. Just before the exception the following output is generated by
the program:
Object constructor of 'main object'
Object constructor of 'local object'
Object fun() of 'main object'
Then the exception is generated, resulting in the next line of output:
Copy constructor for 'local object' (copy)
The throw clause receives the local object, and treats it as a value argument: it creates a copy of the
local object. Next, the exception is processed. The local object is destroyed, and the catcher catches
an Object, which again is a value parameter. Hence, another copy is created. We see the following
lines:
Object destructor of 'local object'
Copy constructor for 'local object' (copy) (copy)
Now the message inside the catcher is displayed, and the hello member of the object received by the
catcher is called, showing us once again that we received a copy of the copy of the local object of the
fun() member function:
Caught exception
Hello by 'local object' (copy) (copy)
Now the program terminates, and the still living objects are destroyed in their reversed order of
creation:
Object destructor of 'local object' (copy) (copy)
Object destructor of 'local object' (copy)
Object destructor of 'main object'
If the catcher would have implemented so as to receive a reference to an object (catch (Object &o)),
the double copy would have been avoided. In that case the output of the program would have been:
Object constructor of 'main object'
Object constructor of 'local object'
Object fun() of 'main object'
Copy constructor for 'local object' (copy)
Object destructor of 'local object'
Caught exception
Hello by 'local object' (copy)
Object destructor of 'local object' (copy)
Object destructor of 'main object'
showing that only a single copy of the local object is used.
Of course it's a bad idea to throw a pointer to a locally defined object: the pointer is thrown, but the
object to which the pointer refers dies once the exception is thrown, and the catcher receives a wild
pointer. Bad news.
Summarizing, local objects are thrown as copied objects, pointers to local objects should not be
thrown. However, it is possible to throw pointers or references to dynamically generated objects,
taking care that the generated object is properly deleted when the generated exception is caught.
Exceptions are thrown in situations where a function can't continue its normal task anymore,
although the program is still able to continue. Imagine a program which is an interactive calculator.
The program continuously requests expressions, which are then evaluated. In this case the parsing of
the expression may show syntax errors, and the evaluation of the expression may result in
expressions which can't be evaluated, e.g., because of the expression resulting in a division by zero.
A bit more sophistication would allow the use of variables, and non-existing variables may be
referred to.
Throw point can be in a deeply nested scope within a try block or in a deeply nested
function call. In. any case, control is transferred to the catch statement.
Summary
Exceptions are peculiar problems that a program may encounter at run time.
Exceptions are of two types: synchronous and asynchronous. c++ provides mechanism
for handling synchronous exceptions.
An exception is typically caused by a faulty statement in a try block. The statement discovers
the error and throws it, which is caught by a catch statement.
The catch statement defines a block of statements to handle the exception appropriately.
When an exception is not caught, the program is aborted.
A try block may throw an exception directly or invoke a function that throws an exception.
Irrespective of location of the throw point, the catch block is placed immediately after the try
block.
Question
Explain basic concept on exception handling in c++ with suitable example?
What are the advantages of using exception-handling mechanism in a program?
What should be placed inside Try Block
Explain Throwing mechanism?
UNIT I
LESSON 31
EXCEPTION HANDLING II
Objective
Catching Mechanism
CATCHING MECHANISM
As stated earlier, code for handling exceptions is included in catch blocks. A catch block looks like
a function definition and is of the form
catch(type arg)
{
// Statements for
// managing except ions
}
The type indicates the type of exception that catch block handles. The parameter arg is an optional
parameter name. Note that the exception-handling code is placed between two braces. 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.
If the parameter in the catch statement is named, then the parameter can be used in the exception-
handling code. After executing the handler, the control goes to the statement immediately
following the catch block.
Due to mismatch, if an exception is not caught, abnormal program termination will occur.
11isimportant to note that the catch block is simply skipped if the catch statement does not catch
an exception.
Multiple Catch Statements
It is possible that a program segment has more than one condition to throw an exception. In such
cases, we can associate more than one catch statement with a try (much like the conditions in a
switch statement) as shown below:
Try
{
// try block
}
catch(typel arg)
{
// catch blockl
}
catch (type2 arg)
{
// catch b1ock2
}
…….
…….
catch(typeN arg)
{
// catch b1ockN
}
When an exception is thrown, the exception handlers are searched in order for an appropriate
match. The first handler that yields a match is executed. After executing the handler, the control
goes to the first statement after the last catch block for that try. (In other words, all other handlers
are bypassed). When no match is found, the program is terminated.
It is possible that arguments of several catch statements match the type of an exception. In such
cases, the first handler that matches the exception type is executed.
Program shows a simple example where multiple catch statements are used to handle; various
types of exceptions.
Multiple catch statement Program
#include <iostream.h>
using namespace std;
void test(int x)
{
try
{
if(x = = 1) throw x; // int
else
if(x = = 0) throw ‘x’; // char
else
if(x = = -1) throw 1.0; // double
cout<< “end of try block \n”;
}
catch(char c) //catch 1
{
cout<< “Caught a character \n”
}
catch(int m) //catch 2
{
cout<< “Caught an integer \n”
}
catch(double d) //catch 3
{
cout<< “Caught a double \n”
}
cout<< “End of try-catch system \n\n”;
}
}
int main( )
{
cout<< “Testing Multiple Catches”
cout<<” x= = 1 \n”;
test( 1 );
cout<<” x= = 0 \n”;
test( 0 );
cout<<” x= = -1 \n”;
test( -1 );
cout<<” x= = 2 \n”;
test( 2 );
return 0;
}
The output of the Program
Testing Multiple Catches
x = = 1
Caught an integer
End of try-catch system
x = = 0
Caught a character
End of try-catch system
x = = -1
Caught a double
End of try-catch system0
x = = 2
End of try-block
End of try-catch system
The program when executed first, invokes the function test( ) with x = 1 and therefore throws x an
int exception. This matches the type of the parameter m in catch2 and therefore catch2 handler is
executed. Immediately after the execution, the function test( ) is again invoked with x = 0. This
time, the function throws 'x', a character type exception and therefore the first handler is executed.
Finally, the handler catch3 is executed when a double type exception is thrown. Note that every
time only the handler, which catches the exception, is executed and all other handlers are
bypassed.
When the try block does not throw any exceptions and it completes normal execution,
control passes to the first statement after the last catch handler associated with that try block.
Point :
Try block does not throw any exception, when the test( ) is invoked with x = 2.
The default catcher
In cases where different types of exceptions can be thrown, only a limited set of handlers may be
required at a certain level of the program. Exceptions whose types belong to that limited set are to
be processed, all other exceptions are treated differently, e.g., they are passed on to an outer level
of exception handling.
Here is an example showing the use of a default exception handler:
try
{
// this code may throw
// different types of
// exceptions
}
catch (char *message)
{
// code to process
// char pointers
}
catch (int value)
{
// code to process
// ints
}
catch (...)
{
// code to process other exceptions,
// often passing the exception on
// to outer level exception handlers:
throw;
}
The reason for passing unspecified exceptions on to outer level exception handlers is simply the
fact that they are unspecified: how would you process an exception if you don't know its type? In
these situations the outer level exception handlers should of course know what exceptions other
than char *s and ints to expect.
Catch All Exceptions
In some situations, we may not be able to anticipate all possible types of exceptions and
therefore may not be able to design independent catch handlers to catch them. In such
circumstances, we can force a catch statement to catch all exceptions instead of a certain type
alone. This could be achieved by defining the catch statement using ellipses as follows:
Program illustrates the functioning of catch (…)
include <iostream>
using namespace std;
void test(int x)
{
try
{
if(x = = 1) throw x; // int
if(x = = 0) throw ‘x’; // char
if(x = = -1) throw 1.0; // double
}
catch(...)
{ // catch all
catch(...) { // Statements for processing // all exceptions}
cout << "Caught an exception \n";
}
}
int main( )
{
cout << Testing Generic Catch \n";
test(-1);
test(0);
test(1);
return 0;
}
The output of the Program
Testing Generic Catch
Caught an except ion
Caught an exception
Caught an except ion
Note that all the throws were caught by the catch(...) statement.
It may be a good idea to use the catch(...) as a default statement along with other catch
handler so that it can catch all those exceptions which are not handled explicitly.
Note
Remember, catch(...) should always be placed last in the list of handlers. Placing it before other
catch blocks would prevent those blocks from catching exceptions.
Summary
A catch block defined by the keyword catch 'catches' the exception 'thrown' by the throw
statement in the try block, and handles it appropriately
An exception is typically caused by a faulty statement in a try block. The statement
discovers the error and throws it, which is caught by a catch statement.
The catch statement defines a block of statements to handle the exception appropriately.
When an exception is not caught, the program is aborted.
We can place two or more catch blocks together to catch and handle multiple types of
exceptions thrown by a try block.
It is also possible to make a catch statement to catch all types of exceptions using ellipses
as its argument.
It may be a good idea to use the catch(...) as a default statement along with other catch
handler so that it can catch all those exceptions which are not handled explicitly
Remember, catch(...) should always be placed last in the list of handlers
Question
Explain multiple catch statement?
When catch handler is used?
When do we use multiple catch statement?
Give a key advantage and key disadvantage of catch(….)
List the advantages of exception handling
UNIT I
LESSON 32
Group discussion on topics covered
Like
Exceptional handling
Templates
UNIT II
LESSON 33
CLASS IMPLEMENTATION
Objective
Implementation of classes
“
An object, such as a CD Player, a printer, a car, etc, is built from assembling various parts. In
the same way, C++ allows you to group various variables and create a new object called a
class.”
Imagine a company that manufactures shoeboxes hires you to write a program that would help
design and identify those shoeboxes. A shoebox is recognized for its dimensions (length, width,
height), color, and shoe size that a particular box can contain, etc. The variables that characterize
such an object are defined in the program below:
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main( )
{
// Define the characteristics of a shoe box
// The following characteristics are COMPLETELY random
double Length(12.55), Width(6.32), Height(8.74);
string Color("Yellow Stone");
float ShoeSize = 10.50;
// Display the characteristics of the shoe box
cout << "Characteristics of this shoe box";
cout << setiosflags(ios::fixed) << setprecision(2);
cout << "\n\tLength = " << Length << "\n\tWidth = " << Width
cout << "\n\tHeight = " << Height << "\n\tVolume = " <<
Length * Width * Height
cout << "\n\tColor = " << Color << "\n\tSize = " << ShoeSize
<< "\n\n";
return 0;
}
The program would produce:
Characteristics of this shoebox
Length = 12.55
Width = 6.32
Height = 8.74
Volume = 693.22
Color = Yellow Stone Size = 10.50 Press any key to continue...
Unless dealing with one shoebox, this program would be rudimentary to run for each object. The
solution is to create an object called box that groups everything that characterizes the object.
“
Now we will learn how to implement a class…. ”
To create a class, use the class keyword followed by a name for the object. Like any other declared
variable, the class declaration ends with a semi-colon. The name of a class follows the rules we
have applied so far for variable and function names. To declare a class called ShoeBox, you would type the following:
class ShoeBox;
As a name that represents a group of items, a class has a body that would be used to define the
items that compose it. The body of a class starts with an opening curly bracket "{" and ends with a
closing one "}". Therefore, another way to create a class is:
class ClassName
{
};
This could also be created as:
Class ClassName
{
};
Either of these techniques produces the same effect.
Since a class is built from combining other identifiers, you will list each variable inside of the body
of the class. Each item that composes the class is represented as a complete variable declared with
a data type and a name. As a variable, each declaration must end with a semi-colon.
Continuing with our shoebox object, you could create it using the class as follows:
class ShoeBox
{
double Length, Width, Height;
char Color[12];
float ShoeSize;
};
The items that compose a class are called members of the class.
“Now that we have understood how to implement a ‘class’, we will now understand about
accessing the class and the components within it..”
Accessing a Class
A common object in real life is visibly made of two categories of parts: those you can see or touch
and those you do not have access to. The parts you can see or touch are considered visible or
accessible. In C++, such parts are referred to as public. Those you cannot see or touch are
considered hidden. In C++, such parts are referred to as private. Like objects in real life, a class is
made of sections that the other functions or other objects cannot “see” and those the other objects
can access. The other objects of of the program are sometimes referred to as the clients of the
object. The parts the client of an object can touch in a class are considered public and the others
are private.
When creating a class, you will define which items are public and which ones are private. The
items that are public are created in a section that starts with the public keyword followed by a
semi-colon. The others are in the private section. If you do not specify these sections, all of the
members of a class are considered private. For example, all of the members of the previously
defined ShoeBox class are private.
Using the public and private sections, our shoebox object can be created as:
class ShoeBox
{
public:
double Length, Width, Height;
string Color;
private:
float ShoeSize;
};
The public and private keywords are referenced by their access level because they control how
much access a variable allows. You can create as many public sections or as many private sections
as you want.
For example, the above class could be created as:
class ShoeBox
{
public:
double Length, Width, Height;
public:
string Color;
double Volume;
private:
float ShoeSize;
private:
char Material;
string Color;
};
When creating a class with different public and private sections, all of the declared variables under
an access level keyword abide by the rules of that access level. The fact that you use different
public sections does not by any means warrant different public levels to the variables. A variable
declared as public in one public section has the same public level of access as any other variable
that is declared in another public section.
A variable that is declared in a class is called a member of the class. Once the class has been
defined, you can use it as an individual variable.
“ Now lets understand how ‘class members’ are declared..”
After defining a class, you can declare it as a variable using the same syntax we have used for any
other variable. A class is declared using its name followed by a name for the defined variable and
ending with a semi-colon. For example, our ShoeBox class can be declared as follows:
ShoeBox Shake;
When an object has been declared, you can access any of its members using the member access
operator "." [Dot operator]. First, type the name of the object variable, followed by a period,
followed by the name of the member you want to access. For example, to access the member
Length of the above class, you would write:
Shake.Length;
Using this syntax, you can display the value of a class member:
cout << Shake.Length;
or you can request its value from the user, using the cin operator. Here is an example:
cin >> Shake.Lengh;
Using the cout extractor to display the values of the object members, our program could be as
follows:
#include <iostream>
#include <string>
using namespace std;
class ShoeBox
{
public:
double Length, Width, Height;
string Color;
private:
float ShoeSize;
};
int main( )
{
ShoeBox Shake; // Display the characteristics of the shoe box
cout << "Characteristics of this shoe box";
cout << "\n\tLength = " << Shake.Length
<< "\n\tWidth = " << Shake.Width
<< "\n\tHeight = " << Shake.Height
<< "\n\tVolume = " << Shake.Length * Shake.Width *
Shake.Height
<< "\n\tColor = " << Shake.Color
<< "\n\tSize = " << Shake.ShoeSize
<< "\n\n";
return 0;
}
“At this time, if you observe very carefully there is a problem? The problem is because we are
trying to access a ‘private member’ of the ‘class’, and we know the restrictions of a ‘private
section’ of a class its obvious that the program would produce the following error.”
[C++ Error] <filename.cpp>(30): E2247 'ShoeBox::TShoeSize' is not accessible
“Even if you change the ShoeSize member access from private to public, the program would
render unpredictable results because the members have not been given appropriate values.”
Characteristics of this shoe box Length = 0 Width = 1.79571e-307 Height = 4.17266e-315 Volume
= 0 Color = Size = 3.58732e-43Press any key to continue...
Techniques of Initializing a Class
“Now that we have learnt how to declare a class and its members, we will now concentrate on
class initialization.”
There are various techniques used to initialize a class: initializing individual members or
initializing the class as a whole. To initialize a member of a class, access it and assign it an
appropriate value.
#include <iostream>
#include <string>
using namespace std;
class ShoeBox
{
public:
double Length, Width, Height;
string Color;
float ShoeSize;
private:
};
int main( )
{
ShoeBox Shake;
double Volume; // Initializing each member of the class
Shake.Length = 12.55;
Shake.Width = 6.32;
Shake.Height = 8.74;
Shake.Color = "Yellow Stone";
Shake.ShoeSize = 10.50;
Volume = Shake.Length * Shake.Width * Shake.Height;
// Display the characteristics of the shoe box
cout << "Characteristics of this shoe box";
cout << "\n\tLength = " << Shake.Length
<< "\n\tWidth = " << Shake.Width
<< "\n\tHeight = " << Shake.Height
<< "\n\tVolume = " << Volume
<< "\n\tColor = " << Shake.Color
<< "\n\tSize = " << Shake.ShoeSize << "\n\n";
return 0;
}
This time, the program would render a reasonable result.
You can also initialize an object as a variable. This time, type the name of the variable followed by
the assignment operator, followed by the desired values of the variables listed between an opening
and a closing curly brackets; each value is separated with a comma. The first rule you must keep in
mind is that the list of variables must follow the order of the declared members of the class. The
second rule you must observe is that none of the members of the class must be another class. In the
following example, one of the members of the class is another class, namely a string. Because of
the way a variable of the class is declared, the program would not compile:
#include <iostream>
#include <string>
using namespace std;
class ShoeBox
{
public:
double Length, Width, Height;
string Color;
float ShoeSize;
private:
};
int main( )
{
// Declaring and initializing the class as a variable
ShoeBox LadyShake = { 12.55, 6.32, 8.74, "Yellow Stone",
10.50 };
Double Volume = LadyShake.Length * LadyShake.Width *
LadyShake.Height;
// Display the characteristics of the shoe box
cout << "Characteristics of this shoe box";
cout << "\n\tLength = " << LadyShake.Length
<< "\n\tWidth = " << LadyShake.Width
<< "\n\tHeight = " << LadyShake.Height
<< "\n\tVolume = " << Volume
<< "\n\tColor = " << LadyShake.Color
<< "\n\tSize = " << LadyShake.ShoeSize << "\n\n";
return 0;
}
Summary
To create a class, use the class keyword followed by a name for the object. Like any
other declared variable, the class declaration ends with a semi-colon.
Each item that composes the class is represented as a complete variable declared with a
data type and a name
Like objects in real life, a class is made of sections that the other functions or other
objects cannot "see" and those the other objects can access
The other objects of of the program are sometimes referred to as the clients of the
object. The parts the client of an object can touch in a class are considered public and
the others are private.
When creating a class, you will define which items are public and which ones are
private.
The public and private keywords are referenced by their access level because they
control how much access a variable allows.
A variable that is declared in a class is called a member of the class
When an object has been declared, you can access any of its members using the
member access operator "." [Dot operator].
You can also initialize an object as a variable.
Question
Define class? Explain implementation of class with suitable example?
Explain the access modifier in class & explain how they differ from each other?
UNIT II
LESSON 34
IMPLEMENTATION II
Objective
Object concepts
Making instance of object:
#include <iostream>
#include <string>
class ShoeBox
{
private:
double Length, Width, Height;
public:
ShoeBox()
{
}
ShoeBox(double L1, double W1, double H1)
{
Length=L1;
Width= W1;
Height=H1;
}
void display()
{
cout<<endl<<Length<<Width<<Height;
}
};
void main( )
{
ShoeBox s1(10,20.66,15);
ShoeBox s1(5,3.89,9);
Cout<<endl<<sizeof(s1);
Cout<<endl<<sizeof(s2);
}
In our program there are Two objects of the type ShoeBox, so there are two instance of Length,
Width, Height in memory. So Length, Width & Height are instance of object. However there is
only one instance of two constructor functions and the display() function. All the objects of class
share these functions.
Tuning Objects
“Similar to tuning a radio set in order to get clear and error free reception, we can tune objects
of a class by specifying applying certain techniques and implementing certain tools which make
object programming all the more powerful.”
There are other features you can apply to make your objects more professional and less prone to
errors. These include constant arguments, constant, private, and inline methods, etc.
Constant Arguments
When studying functions, we learned that when a function receives an argument that it does not
modify, the argument should be declared as constant. This allows the compiler to make sure the
argument would not be modified. The same technique applies to an argument used by a method of
an object.
To declare an argument of an object’s method as constant, type the const keyword on the left of the
argument’s data type. To improve our ShoeBox object, we would like to know the area of each
side because different things will be displayed on each side and we need to know how much space
is available. If we were dealing with a rectangle, we would just declare an Area( ) method as
follows:
Double Area( );
On a box (rectangular parallelepiped), we have three rectangles types that represent the six faces.
We can declare one method that takes any two sides and calculates their area. Such a method
would be declared as follows:
double Area(Double Side1, Double Side2);
After declaring it in the public section, we would define it as follows:
double ShoeBox::Area(Double Side1, Double Side2)
{
return Side1 * Side2;
}
In the Display( ) method, we could display the area of the length by the height using:
cout << “\n\tArea = “ << Area(Length, Height);
As you can see, the Side1 and Side2 arguments are not modified; therefore, they should be
declared as constants. To declare each as constant, we would change the declaration of the method
as follows:
Double Area(const Double Side1, const Double Side2);
And we would define it as follows:
double ShoeBox::Area(const Double Side1, const Double Side2)
{
return Side1 * Side2;
}
For an example such as this one, the const keyword can be typed before or after the data type, the
result would be the same. If a method is receiving more than one argument, their constancy is
independent: the fact that one of them needs to be constant does not imply anything about the
other(s).
To help the method specify what side it is calculating the area, we could provide a string that
names the side. We could declare the method as follows:
void Area(const Double Side1, const Double Side2, PChar SideName);
We would then define the new method as follows:
void ShoeBox::Area(const Double S1, const Double S2, PChar n)
{
cout << "\nThe area of the " << n << " side is: " << S1 * S2;
}
In the Display( ) method, we could specify the name of the side and provide the corresponding
measures as follows:
Area(Length, Height, "front");Area(Length, Width, "top");Area(Width, Height, "left");
Here is the complete implementation:
#include <iostream>
#include <string>
using namespace std;
class ShoeBox
{public:
double CalcVolume( )
{
return Length * Width * Height;
}
void Area(const double Side1, const double Side2, char SideName[]);
float CalcShoeSize( )
{
return Length - 0.35;
}
void Display( );
private:
double Length;
double Width;
double Height;
char Color[32];
};
void ShoeBox::Area(const double S1, const double S2, char N[])
{
cout << "\nThe area of the " << N << " side is: " << S1 * S2;
}
void ShoeBox::Display( )
{
// Initializing the dimensions
Length = 10.42;
Width = 5.28;
Height = 5.88;
Color = "Yellow Stone";
// Display the characteristics of the shoe box
cout << "Characteristics of this shoe box";
cout << "\nDimensions(L*H*W) = "
<< Length << " * " << Height << " * " << Width;
Area(Length, Height, "front");
Area(Length, Width, "top");
Area(Height, Width, "left");
cout << "\n\tVolume = " << CalcVolume( )
<< "\n\tColor = " << Color
<< "\n\tSize = " << CalcShoeSize( );
}
int main( )
{
ShoeBox Bambou;
Bambou.Display( );
return 0;
}
Constant Methods
Some of the method members of an object, though using member variables of the same object, do
not modify them. To make sure that such a method does not alter the value of a member variable,
the method should be declared and implemented as constant.
To declare a method as a constant, add the const keyword to the right side of the method when
declaring it. Here is an example:
string SpecFullName( ) const;
The CalcVolume( ) and the CalcShoeSize( ) methods do not modify the member variables they
receive. You can reinforce this by declaring them as const:
double CalcVolume( ) const;float CalcShoeSize( ) const;
When implementing the method, type the const keyword on the right side of the method’s closing
parenthesis:
double ShoeBox::CalcVolume( ) const
{
return Length * Width * Height;
}
float ShoeBox::CalcShoeSize( ) const
{
return Length - 0.35;
}
If you decide to define constant methods locally (inline), the only difference is to remove the semi-
colon of the end of the declaration and define the method normally.
Notice that the Display( ) method assigns values to the member variables, which means it alters
their values. Therefore, it cannot be declared or defined as constant. Here is the new version of our
ShoeBox object:
class ShoeBox
{
public:
double CalcVolume( ) const
{
return Length * Width * Height;
}
void Area(const double Side1, const double Side2, char SideName[]);
float CalcShoeSize( ) const
{
return Length - 0.35;
}
void Display( );
private:
double Length;
double Width;
double Height;
string Color;
};
The program would still produce the same result.
Private Methods
At this time, we know that one of the responsibilities of a member method of an object is to carry
assignments. Another job performed by methods is to communicate with the clients of an object.
As you might have found out, some of the methods of an object are exclusively used to carry
assignments. The external functions or other objects do not call such methods and do not
communicate with them. If you create a class and know that a particular member method is not
used to transfer data to the client methods, you can declare such a method as private, just like you
would do with a member variable.
To declare a method as private, include it in the private section of the object. To implement it,
follow the same rules we have learned about implementing the methods of an object. The biggest
difference you must keep in mind (which will also be very important when we learn about
inheritance) is that this function method is not available to the outside world. Here is an example:
class Employee
{
public:
void IdentifyEmployee( );
string FullName( ) const { return FirstName + " " + LastName; }
void GetHourlySalary( );
void CalcTotalHours( );
void Display( );
void CalcNetPay( )
{
if( IsMarried( ) == false )
NetPay = GrossPay - (GrossPay * 30 / 100);
else
NetPay = GrossPay;
}
private:
void CalcGrossPay( );
bool inline IsMarried( ) const;
string FirstName;
string LastName;
double TotalHours;
double HourlySalary;
double WeeklySalary;
double GrossPay;
double NetPay;
};
Objects and Their Implementations
An object is made of the material that compose it and the actual structure of the object, which
defines how the object is built and used. This means, a class is be made of two parts: its building
block and its definition. These two parts of a class can be kept in different files that have access to
each other.
Class' Header File
The building block or foundation of an class is made of the class' creation, listing all of its
members. This foundation is created in a file called a header file, similar to the one we learned
when studying functions. The name of the file follows the naming rules we have applied so far.
The header file has an extension of .h.
You create an object’s header file the same we did when studying functions. To create the header
file, you can just define the class as an object. If some of the members are defined in files outsde of
the object, include their header file(s).
Here is what our ShoeBox header file would look like:
#include <iostream>
#include <string>
using namespace std;
class ShoeBox
{
public:
double CalcVolume( ) const
{
return Length * Width * Height;
}
void Area(const double Side1, const double Side2, char SideName[32]);
float CalcShoeSize( ) const
{
return Length - 0.35;
}
void Display( );
private:
double Length;
double Width;
double Height;
string Color;
};
Class Source Code
This file used to implement the object is called a source file. It is used to define what the object is
supposed to do. It contains all or some of the methods and their implementations.
To create the source file, from the New property page of the New Items dialog box, click the Cpp
File icon and click OK. By default, the (first) file is called File1.cpp. To change that name, you
must save the project and replace the name of the file with the desired name.
A source file should at least start with a line that specifies the name of the header file that it is
implementing. Since this file is usually created in the same project, it is specified with an include
line that is encloses the file name with double-quotes. An example would be:
#include "Book.h"
The main area of the file is made of the class' implementation. Here is what the source file of our
ShoeBox would look like:
#include "File1.h"
void ShoeBox::Area(const Double S1, const Double S2, PChar N)
{
cout << "\nThe area of the " << N << " side is = " << S1 * S2;
}
void ShoeBox::Display( )
{ // Initializing the dimensions
Length = 14.32;
Width = 8.36;
Height = 6.54;
Color = "Brown Carpet";
// Display the characteristics of the shoe box
cout << "Characteristics of this shoe box";
cout << "\nDimensions(L*H*W) = "
<< Length << " * " << Height << " * "
<< Width; Area(Length, Height, "front");
Area(Length, Width, "top");
Area(Height, Width, "left");
cout << "\n\tVolume = " << CalcVolume( )
<< "\n\tColor = " << Color
<< "\n\tSize = " << CalcShoeSize( );
}
The main( ) function of our shoe box project is reduced to simply calling the appropriate ShoeBox
method member:
#include <iostream.h>
#include "ShoeBox.h"
int main( )
{
ShoeBox Sala;
Sala.Display( );
return 0;
}
Summary
To declare an argument of an object's method as constant, type the const keyword on
the left of the argument's data type.
some of the methods of an object are exclusively used to carry assignments. The
external functions or other objects do not call such methods and do not communicate
with them.
To declare a method as private, include it in the private section of the object.
An object is made of the material that compose it and the actual structure of the object,
which defines how the object is built and used
a class is be made of two parts: its building block and its definition. These two parts of
a class can be kept in different files that have access to each other.
Question what is an object? Explain implementation of objects & instance of object?
What do u understand instance of objects?
UNIT II LESSON 35
DATA DRIVEN
Objective Data driven concept
Introduction
A Dynamic Data Driven Application System (DDDAS) is an application software system capable
of accepting and effectively utilizing remote data in real time (i.e., during the execution of the
application software). Many software systems currently utilize static input data, i.e., input data
which is specified a priority. The key concept of DDDAS is the generalization of application
software systems to dynamically utilize real-time data arising from remote experiment and
simulation, and to control such remote experiment and simulation to improve the performance of
the application software system. The concept is illustrated
schematically in Fig. 1.
Dynamic Data Driven Application Systems have become a major subject of research interest due
to the continuing rapid advances in technology. These include, for example, improvements in
computer processor performance (i.e. doubling every 18 to 24 months (Berkowitz 1996)), network
bandwidth, Rapid Prototyping (RP) and real-time data acquisition and control (e.g., using Micro-
Electro Mechanical Systems (MEMS)). These rapid technological advances provide the means to
revolutionize the use of existing and future application software systems. For example, the NSF
TeraGrid1 is a multi-year e_ort to deploy20 TFlops of computing capacity at five sites connected
through a 40 Gbps network.
The Tera Grid will o_er unprecedented remote computing capability which can be utilized in real-
time by application software systems executing at users’
sites. The incorporation of the NSF Tera grid into an application software system
is therefore an example of a Dynamic Data Driven Application System.
1 http://www.ncsa.uiuc.edu/About/TeraGrid/
Conventional Engineering Design Optimization Engineering design is a potential Dynamic Data
Driven Application System Where in remote real-time input from high performance computing
resources
(e.g., NSF Tera grid) and experiment (e.g., using capability for rapid fabrication of new
experimental configurations) can produce a better design in shorter time with lower cost than the
conventional approach. Fig. 2 illustrates the conventional approach to engineering design. An
initial design is typically evaluated using simulation software executing on local computer
resources. An example is Computational Fluid Dynamics (CFD) simulation using one of the
several available commercial CFD software packages (e.g., fluent, gasp, star-cd). The results of the
simulation are reviewed by the designer and additional simulations performed as needed. An
experiment is then planned and executed, and the results compared with the simulation. The
process is iterated until a satisfactory design has been achieved. A major limitation of the
conventional approach is the absence of synergistic real-time use of remote experimental data and
high performance computer resources (e.g., the NSF Tera Grid).
4 Data Driven Design Optimization Methodology
We are developing an integrated software system, denoted Data Driven DesignOptimization
Methodology (DDDOM), to synergistically incorporate remote experiment and simulation into an
automated design optimization methodology. The DDDOM is comprised of six elements as
illustrated in Fig. 3 and are summarized below. Controller The DDDOM Controller provides
direction and control of the design optimization process. It is written in Perl (Wall et al 2000), a
powerful systems programming language which enables robust program control on local and
remote systems. The Controller utilizes the Globus software system (Foster and Kesselman 1997)
to link to the NSF Tera Grid. User Interface The User Interface provides for the initiation and
monitoring of the design optimization. It also provides visualization of the intermediate results of
the design optimization process. The interface is written in Perl/Tk (Lidie and Walsh 2002). Both
Perl and Perl/Tk operate on virtually every platform and operating system.
Optimizer A Multi-Criteria Design Optimization (MDO) algorithm is used to search the design
space to define the Pareto Set. Both local (i.e., gradient-based) and global (i.e., stochastic-based)
algorithms are used. Examples are CFSQP(Lawrence et al 1994) and GADO (Rasheed and
Hirsh 1999), respectively.Surrogate Model Surrogate Models of the objective functions f are
developedduring the design optimization using experiment and simulation. Thesemodels are
utilized by the optimizer to search the design space for the ParetoSet. We utilize Response
Surfaces (Myers and Montgomery 1995) and Radial
Basis Function Artificial Neural Networks (Hertz et al 1991). The SurrogateModel incorporates
the measure of uncertainty _ in the results generated by theexperiment and simulation.
Experiment : Experiments are performed in real-time with the conditions of the experiment
defined by the Controller. The interface with experiments is typically National Instruments Lab
View (Travis 2002). Rapid Prototyping is used to build new models as needed with minimal
delay (e.g., one day).
Simulation : Simulations can be performed locally (i.e., at the same site as the DDDOM is
operated) or remotely (e.g., on the NSF Tera Grid). The simulations are performed in real-time
with the conditions of the simulation defined by the Controller.
5 Example
A five minute demonstration has been developed to illustrate the principle of operation of the
DDDOM. The limited duration of the demonstration precludes the actual use of RP which
typically requires several hours for fabrication of the prototype for experiment. Therefore, we have
selected a single experimental con-
figuration. Nonetheless, the experiment provides data to the DDDOM Controller in real time, and
the Controller directs the experiment, thereby illustrating the DDDOM concept.
The specific problem is defined as follows. Consider the flow of air in a converging-diverging
nozzle attached to a stagnation chamber as illustrated in Fig.The nozzle is designed to achieve
Mach 2 at the exit assuming isentropic expansion throughout the nozzle. Depending upon the ratio
of stagnation pressure pt1 to ambient pressure pa, the flow in the diverging section of the nozzle
can be 1) subsonic everywhere, 2) supersonic and subsonic with a normal shock at some location
in the diverging section, and 3) supersonic everywhere (Anderson 2003). In the latter case, the
theoretical exit Mach number is two. A one-dimensional simulation based upon inviscid gas
dynamics (Liepmann and Roshko 1957) indicates that the exit pressure ratio pe vs stagnation
pressure pt1 behaves as shown by the curve denoted Simulation in Fig. 5. This behavior
is idealized, however, due to the neglect of the viscous boundary layer on the nozzle walls and the
e_ect of the interaction of the normal shock wave (if it exists) with the boundary layers.
Consequently, the actual exit pressure pe vs stagnation pressure pt1
curve di_ers substantially from the idealized shape.
Data Driven Design Optimization Methodology
A Dynamic Data Driven Application System
1 Introduction
A Dynamic Data Driven Application System (DDDAS) is an application softwaresystem capable
of accepting and effectively utilizing remote data in realtime (i.e., during the execution of the
application software). Many software systemscurrently utilize static input data, i.e., input data
which is specified apriori. The key concept of DDDAS is the generalization of application
softwaresystems to dynamically utilize real-time data arising from remote experiment
andsimulation , and to control such remote experiment and simulation to improvethe
performance of the application software system. The concept is illustratedschematically in Fig.
1.
Dynamic Data Driven Application Systems have become a major subject of research interest due
to the continuing rapid advances in technology. These include, for example, improvements in
computer processor performance (i.e., doubling every 18 to 24 months (Berkowitz 1996)), network
bandwidth, Rapid Prototyping (RP) and real-time data acquisition and control (e.g., using Micro-
Electro Mechanical Systems (MEMS)). These rapid technological advances provide the means to
revolutionize the use of existing and future application software systems. For example, the NSF
TeraGrid1 is a multi-year e_ort to deploy 20 TFlops of computing capacity at five sites connected
through a 40 Gbps network. The TeraGrid will o_er unprecedented remot computing capability
which can be utilized in real-time by application software systems executing at users’ sites. The
incorporation of the NSF Teragrid into an application software system is therefore an example of a
Dynamic Data Driven Application System.
Group discussion session on the article Function Decomposition and the differences
between two
Summary
6 Conclusions
Engineering design is an example of a Dynamic Data Driven Application System Where in real-
time data from experiment and simulation can be effectively utilized to yield better designs in
shorter time. A Data Driven Design Optimization Methodology (DDDOM) is being developed
which incorporates experiment and simulation in a real-time, synergistic manner. The theory and
organization of DDDOM is described. An example demonstration is described.
UNIT II
LESSON 36
ANALYSIS AND DESIGN METHODS
Formal(OMT) object based design methods
Objective
Purpose of method
S/W life cycle
What is the Purpose of a Method?
A method defines a reproducible path for obtaining reliable results. All knowledge-based
activities use methods that vary in sophistication and formality. Cooks talk about recipes, pilots go
through checklists before taking off, architects use blueprints, and musicians follow rules of
composition.
Similarly, a software development method describes how to model and build software
systems in a reliable and reproducible way.
In general, methods allow the building of models from model elements that constitute the
fundamental concepts for representing systems or phenomena.. The object-oriented approach to
software development proposes the equivalent of notes – objects – to describe software.
Methods also define a representation – often graphical – that allows both the easy manipulation of
models, and the communication and exchange of information between the various parties involved.
A good representation seeks a balance between information density and readability.
Over and above the model elements and their graphical representations, a method defines the rules
that describe the resolution of different points of view, the ordering of tasks and the allocation of
responsibilities. These rules define a process that ensures harmony within a group of cooperating
elements, and explains how the method should be used.
As time goes by, the users of a method develop a certain 'know-how' as to the way it should be used.
This know-how, also called experience, is not always clearly formulated, and is not always easy to
pass on.
From Functional to Object-Oriented Methods
Although object-oriented methods have roots that are strongly anchored back in the 60s, structured
and functional methods were the first to be used. This is not very surprising, since functional
methods are inspired directly by computer architecture (a proven domain well known to computer
scientists). The separation of data and code, just as exists physically in the hardware, was translated
into the methods; this is how computer scientists got into the habit of thinking in terms of system
functions.
This approach is natural when looked at in its historical context, but today, because of its lack of
abstraction, it has become almost completely anachronistic. There is no reason to impose the
underlying hardware on a software solution. Hardware should act as the servant of the software that
is executed on it, rather than imposing architectural constraints.
More recently, towards the beginning of the 80s, object-oriented methods started re-emerging.
History – with a big H – is said to repeat itself. The lesser history of methods repeats itself as well:
the paths followed by functional methods and object-oriented methods are similar. To begin with,
there was programming, with subprograms and objects as alternatives for the basic elements of
structure. A few years later, software scientists pushed the idea of structure towards design as well,
and invented structured
design in one instance, and object-oriented design in the other. Later again, progress was
made in the area of analysis, always using the same paradigm, either functional or object-
oriented. Both approaches are therefore able to provide a complete path across the whole
software lifecycle.
The evolution of methods, whether object-oriented or not, always progresses from programming
towards analysis.
In practice, the situation is a bit more complex – methods often do not cover the full lifecycle. This
results in methods being mixed and matched: method A is used for analysis followed by method B,
which is used for the design. As long as it uses a single paradigm – the functional approach or the
object-oriented approach – this compartmentalization remains reasonable. Although it may remain
understandable, the mixture of paradigms is clearly less reasonable.
Towards the mid-80s, the benefits of object-oriented programming began to gain recognition, and
object design seemed like a sensible approach for people who wanted to use an object-oriented
programming language such as Smalltalk. However, from the analysis standpoint, the concept of
object-orientation was still only vapor and supposition. At that time, corporations had developed a
strong knowledge of functional analysis and semantic data modeling methods. Computer scientists
were inclined to follow a functional analysis phase with an object-oriented design phase.
This approach has serious drawbacks attached to the paradigm shift. Moving from a functional
approach to an object-oriented one requires a translation of the functional model elements into object
model elements, which is far from being straightforward or natural. Indeed, there is no direct
relationship between the two sets, and it is therefore necessary to break the model elements from one
approach in order to create model element fragments that can be used by the other. This paradigm
shift, right in the middle of the development effort, can greatly hinder the navigation from the
statements of requirements obtained early in the analysis phase, to the satisfaction of those
Requirements in the design phase. Moreover, an object-oriented design obtained after translation
very often lacks abstraction, and is limited to the encapsulation of low-level objects available in the
implementation and execution environments. All this implies a great deal of effort in order to obtain
results that are not very satisfactory.
The combination of a functional approach for analysis and an object-oriented approach for design
and implementation does not need to exist today, as modern object-oriented methods cover the full
software lifecycle
During the past decade, object-oriented applications – going from requirements analysis to
implementation – have been developed in all sectors of programming. The experience acquired on
these projects has helped the understanding of how to join together the various activities required to
support a fully object-oriented approach. To date, the evolution of these practices is not complete,
and there are still a few advocates of the mixed approach, prisoners beneath the weight of their
habits. Corporations that are on the brink of the transition to object-orientation should not reproduce
this flaw. It is far easier to deploy an approach that is completely object-oriented. In addition,
software developed using this approach is simpler, more reliable and more easily adapted to the
expectations of its users.
The Proliferation of Object-Oriented Methods
The first few years of the 90s saw the blossoming of around fifty different object-oriented methods.
This proliferation is a sign of the great vitality of object-oriented technology, but it is also the fruit of
a multitude of interpretations of exactly what an object is. The drawback of this abundance of
methodologies is that it encourages confusion, leading users to adopt a 'wait and see' attitude that
limits the progress made by the methods. The best way of testing something is still to deploy it;
methods are not cast in stone – they evolve in response to comments from their users.
Fortunately, a close look at the dominant methods allows the extraction of a consensus around
common ideas. The main characteristics of objects, shared by numerous methods, are articulated
around the concepts of class, association (described by James Rumbaugh), partition into subsystems
(Grady Booch), and around the expression of requirements based on studying the interaction
between users and systems (Ivar Jacobson's use cases).
Finally, well-deployed methods, such as Booch and OMT (Object Modeling Technique), were
reinforced by experience, and adopted the methodology elements that were most appreciated by the
users.
Booch and OMT Getting Closer
The second generations of the Booch and OMT methods, called Booch'93 and OMT-
2, were far more similar to one another than their predecessors had been. The remaining differences
were minor, and pertained primarily to terminology and notation. Booch'93 was influenced by OMT
and adopted associations, Harel diagrams and event traces. In turn, OMT-2 was influenced by Booch
and introduced message flows, hierarchical models and subsystems, and model components. More
importantly, it removed data flow diagrams from the functional model. These were inherited
functional baggage and were not well integrated with the overall OMT approach.
By this stage, both methods offered complete lifecycle coverage, but with a notable distinction in
focus. Booch'93 focused on implementation, while OMT-2 concentrated on analysis and abstraction.
Nonetheless, there were no serious incompatibilities between the two methods.
Object-oriented concepts have a history that is often complex and intricate. The elements presented
in the table below emerged from the experience of deploying the various
methods, and have influenced the effort to unify the Booch and OMT methods
Origin Element
Booch Categories and subsystems
Embley Singleton classes and composite objects
Fusion Operation descriptions, message numbering
Gamma et al Frameworks, patterns and notes
Harel Statecharts
Jacobson Use cases
Meyer Pre- and post-conditions
Odell Dynamic classification, emphasis on events
OMT Associations
Shlaer-Mellor Objects lifecycles
Wirfs-Brock Responsibilities and collaborations
Summary
Methods also define a representation – often graphical – that allows both the easy
manipulation of models, and the communication and exchange of information between the
various parties involved.
The evolution of methods, whether object-oriented or not, always progresses from
programming towards analysis.
The second generations of the Booch and OMT methods, called Booch'93 and OMT-2, were
far more similar to one another than their predecessors had been.
OMT-2 was influenced by Booch and introduced message flows, hierarchical models and
subsystems, and model components. More importantly, it removed data flow diagrams from
the functional model.
Questions
1. discuss S/W life cycle
2. Give the details of OMT design method
UNIT IILESSON 37
ANALYSIS AND DESIGN METHODS
CRC Methods
Objective :
Conceptual Overview of CRC cards
Design and analysis method
Conceptual Overview
A CRC cards is an index card that is use to represent the responsibilities of classes and the
interaction between the classes. CRC cards are an informal approach to object oriented modeling.
The cards are created through scenarios, based on the system requirements, that model the behavior
of the system. The name CRC comes from Class, Responsibilities, and Collaborators which the
creators found to be the essential dimensions of object oriented modeling.
CRC cards where introduced by Kent Beck and Ward Cunningham in there paper "A Laboratory for
Teaching Object-Oriented Thinking" released in OOPLSA '89. There original purpose was to teach
programmers the object-oriented paradigm. When Kent Beck wrote the draft version of their paper
he change Collaborators to helpers. Ward Cunningham changed it back to Collaborators when he
reviewed the paper. The initials of Cunningham's son are CRC.
Why uses CRC cards?
They are portable... No computers are required so they can be used anywhere. Even away from the
office.
They allow the participants to experience first hand how the system will work. No computer tool can
replace the interaction that happens by physically picking up the cards and playing the roll of that
object...
They are a useful too for teaching people the object-oriented paradigm.
They can be used as a methodology them selves or as a front end to a more formal methodology
such as Booch, Wirfs-Brock, Jacobson, etc.
Although CRC cards where created for teaching, they have proven useful for much more. They
become an accepted method for analysis and design. The biggest contributing factor to their success
is the fact that they provide an informal and non threatening environment that is productive to
working and learning.
1. The CRC card session.
The Group
The ideal group size for a CRC card session is five or six people. This size generally allows
everyone to productively participate. In groups of large size the productive is cut by more
disagreements and the amount of participation by everyone is lower. If there are more than six
people, one solution is to have the extra people be present strictly as observers.
The group five or six people in the core group should be composed of developers, domain experts,
and an object-oriented technology facilitator. In the initial Analysis phase there should be two or
three domain experts, one object-oriented technology facilitator, and the rest of the group made up of
people how are responsible for delivering the system. As the project moves more in to the design
phase, some of the domain experts can be replaced with developers. There should always be at least
one domain expert in the group to clarify an question that arise about the behavior of the system.
The Cards
The cards should look something like this:
The exact format of the card can be customized to the preferences of the group, but the minimal
required information is the name of the class, it's responsibilities and the collaborators. The back of
the card can be used for a description of the class. During the design phase attributes of the class can
be recorded on the back as well. One way to think of the card is the front as the public information,
and the back as the encapsulated, implementation details.
The Session
Before starting a session there needs to be some kinds of requirements for the systems. Weather they
are implicitly or explicitly define the people participating in the group need to be familiar with them.
A session also needs to focus on one part of the problem at a time. So a subset of the problem needs
to be chosen to explored during the CRC card session.
Creating class
The first step in modeling an system in the object-oriented paradigm is to identify the class in the
problem domain. So this is the first step in a CRC card session. Using the problem statement or
requirements document, identify the classes that are obvious in the subset of the problem that is
going to explored in this session. One useful tool is to find all of the nouns and verbs in the problem
statement. The nouns are a good key to what class are in the system, and the verbs show what there
responsibilities are going to be. Use this information for the basis of a brainstorming session and
identify all the class that you see. Remember in a brainstorming session there should be no or little
discussion of the ideas. Record them and filter the results after the brainstorming. After the classes
have been chosen pass out cards and assign the class to the member of the group. Each person
should be responsible for at least on class. They are the owner of that class for the session. Each
person records the name of their class on a card. One class per card.
Responsibilities
Once a reasonable set of classes have be assigned to the group, responsibilities can be added. Add
responsibilities that are obvious from the requirements or the name of the class. You don't need to
find them all or any. The scenarios will make them more obvious. The advantage of finding some in
the beginning is that it help provide a starting place.
Super classes and Subclasses
Super classes and subclasses can be defined at any time they become obvious. The scenarios will
illuminate these as well. It is up to the group to decided if they want to define any hierarchical
relationships now or wait till the scenarios to do this.
Attributes
Attributes of class don't really need to be defined any time soon. They are an implementation detail.
The responsibilities of the class will help make these clear. Attributes are general not defined at all
till the design phase, but they can be defined at anytime the group thinks it is appropriate. Remember
these are implementation details and should go on the back of the card.
Scenario execution
These are the heart of the CRC card session. Scenarios are walk-throughs of the functions of the
system in detail. Take required functionality from the requirements document and use this as a
scenarios. Start with scenarios that are part of the systems normal operation first, and then
exceptional scenarios, like error recover, later.
First decide which class is responsible for this function. The owner of the class then picks up his
card. When a card is in the air it is an object and can do things. The own announces that he needs to
fulfill his responsibility. The responsibility is refined in to smaller tasks if possible. These smaller
tasks can be fulfilled be the object is appropriate or they can be fulfilled be interacting with other
objects. If no other appropriate class exist, maybe you need to make one. This is the fundamental
procedure of the scenario execution.
Lets move on the Analysis and try out first CRC card session.
2. CRC cards for analysis.
Analysis is the process of modeling what a system does, not how it does it. Lets start by modeling a
sample system using CRC cards.
Activity 1.
Problem statement.
This application will support the operations of a technical library for an R&D organization. This
includes the searching for and lending of technical library materials, including books, videos, and
technical journals. Users will enter their company ids in order to use the system; and they will enter
material ID numbers when checking out and returning items.
Each borrower can be lent up to five items. Each type of library item can be lent for a different
period of time (books 4 weeks, journals 2 weeks, videos 1 week). If returned after their due date, the
library user's organization will be charged a fine, based on the type of item( books $1/day, journals
$3/day, videos $5/day).
Materials will be lent to employees with no overdue lendables, fewer than five articles out, and total
fines less than $100.
...(Design Constraints)...
With this problem statement identify the class and assign them to the group members. Make a card
for each class.
Some ideas for class:
application
library
material
books
videos
journal
company
system
ID numbers
item
borrower
date
organization
employee
article
fine
This list is made up of the nouns in the problem statement. It is up to you to decide which ones if any
are good classes for this problem.
Now lets try our first scenario, taken from the requirement that the system bust allow users to check
out lendables.
"What happens when Johny Codewarrior, who has no accrued fines and one outstanding book, not
overdue, checks out a book entitle Document, Your job depends on it?"
More about Analysis
The strength of CRC cards for analysis.
Common Project Vocabulary -
Spread Domain Knowledge -
Making the Paradigm Shift -
Live Prototyping -
Identifying Holes in Requirements -
When is the analysis done, and time to move on to design? When all the different responsibilities are
in place and the system has become stable. After all the normal behavior has been covered,
exceptional behavior needs to be simulated. When you notice that the responsibilities are all in place
to support the new scenarios, and there is little change to the cards, this is a sign the you are ready to
start design.
Activity 2.
Now let do some more scenarios and try to stabilize our system. Try these:
"What happens when Johny Codewarrior returns the book Document, Your job depends on it two
days late? He has no other item checked out and no acquired fines."
"What happens when Ivar Jacobson uses the search feature to look for the book Object-Oriented
Software Engineering of which there are 2 copies available?"
"What happens when Grady Booch uses the search feature to look for the book Object-Oriented
Analysis and Design with Application of which there is 1 copy available and the database is down?"
3. CRC cards for Design.
In the design phase, the concentration moves from what to how. In this phase developers replace
some of the domain experts in the group, but there still should be one domain expert in the group.
Strength of CRC card for Design
Spreading Objet-Oriented Design Expertise
Design Reviews
Framework for Implementation
Informal Notation
Things to consider in Design
Target Environment
Language
Choice of supporting software components
Performance Requirements
Other - memory, security...
CRC Element at the Design Stage
Classes
Think about what class are need to make the system work. Do you need a List class to hold objects?
Do you need class to handle exceptions? Do you need wrapper classes for other subsystems? New
classes that are looked for in this part, are classes that support the implementation of the system.
Scenarios and Responsibilities
During the problem modeling in the analysis phase the distinction between class and object is blurry.
Now think about the objects in your scenarios. Who create the objects? What happens when it is
created and destroyed? What is the lifetime of the object vs. the lifetime of the information held be
the object?
Attributes
Now is the time to look at what information the objects hold compared to what is requested from
other classes or computed of the fly. Use the back of the card to record the attributes found for the
classes.
New things to record your cards
Sub responsibilities
Break you responsibilities into sub responsibilities and list the sub responsibilities indented under the
main responsibilities. Move the collaborators next to the sub responsibilities that use them.
Collaborating Responsibilities
After the Collaborator class on your card list the responsibility of the used class that is used in the
collaboration.
Data passed
After the collaborating responsibilities on your cards, list the data past back by the collaborating
object in parenthesis.
Activity 3.
Redo the scenarios you did in the analysis phase, but know take in to consideration all of the design
heuristics discussed. Make up your own scenarios and try them...
System Requirements
Cards:
Should be physical cards, not virtual cards. CASE tools for support of CRC cards are useful, but they
cannot replace the interaction that physical cards facilitate.
3x5 or 4x6 are the perferable size. But you can really use anything you want.... Napkins???
Denny's??? Ahh the possiblities are endless...
Summary
A CRC cards is an index card that is use to represent the responsibilities of classes and the
interaction between the classes. CRC cards are an informal approach to object oriented
modeling.
Why uses CRC cards?
They are portable... No computers are required so they can be used anywhere. Even away from the
office.
They allow the participants to experience first hand how the system will work. No computer
tool can replace the interaction that happens by physically picking up the cards and playing
the roll of that object...
They are a useful too for teaching people the object-oriented paradigm.
Questions
1.What is CRC card? Why we are in need of using CRC cards?
UNIT II
LESSON 38
DESIGN REFINEMENT
Objective:
Concept of coupling and cohesion
Design Refinement
Refinement presupposes that implementation is being inherited as well as abstraction.
Refinement has different significance depending on whether the client is another component
entirely, or is a part of B. Clearly any class can be a client of itself (self-dependency would seem
to be non-problematic, but some of the concerns in refinement with base as client cast doubt on
this).
Coupling and Cohesion between modules (i.e., classes).
Specific measures of coupling are:
1. The number of classes that a given class inherits from;
2. The number of classes that a given class references as data members;
3. The number of methods that a given method calls;
4. The number of parameters that a given method has.
Specific measures of cohesion are:
1. The degree to which all methods in a class perform a logically-related aspect of
system functionality
2. The degree to which a method performs a single specific function
In general, coupling should be minimized and cohesion should be maximized.
Techniques to reduce coupling
Limit the number of classes that communicate with (i.e, call functions of) other classes.
I. E.g. in an MVP design, a Process-class method invoked by a View class method
may forward a Model-class exception rather than catching the exception and
calling a View-class method.
II. E.g.,
a. In the Rolodex system, the Process-class method Rolodex Command
Processor. Process Command is called from a View-class method in
Rolodex Command Editor.
b. The process Command method throws an Input Errors exception back
to the view, rather than catching the exception and calling a View
class.
c. This limits coupling by not having a View class reference in the
Rolodex Command Processor process class.
Limit the number of calls between classes that do need to communicate with each other.
I. E.g., in the Rolodex system, the dialog button functions, such as OKAddButton,
can communicate directly with the model, without having to go through a parent
view class.
II. E.g., OKAddButton. ActionPerformed can call Rolodex. Add directly
III. More highly-coupled alternative would be some chain-of-command call such as
AddCardDialog.getRolodex().add.
Limit the number of public functions in each class.
I. In general, make a function public only if there is a demand for it from some other
class.
II. Do not add public get functions "in case" they may be needed; the same goes for
public set functions.
III. E.g., since AddCardDialog.getRolodex is never used, it should not be provided.
Limit the types of function parameters and return values to the smallest type necessary.
I. Consider the Rolodex.find operation.
II. It returns zero or more cards, which could be returned as Rolodex object, or a
simpler CardList object.
III. The Card List object is preferable, since callers of Rolodex.find do not need all of
the information in a full Rolodex, but only a simple list.
Design to limit the amount of change needed if data representations change.
I. When using external process classes (e.g., C++ from Java), design wrapper
classes that define a generic process class that hides details of external class.
II. With a properly designed wrapper class, little or no changes to a Model class are
necessary when changing underlying data representations in Process classes.
Use exception handling wisely.
I. Consider again the use of exception handling to communicate between models
and views.
II. The InputErrors exception classes provide a generic, string-based representation
that can be used uniformly for error communication.
Ease of debugging -- a major rationale for limiting coupling.
I. Consider the debugging question: "If something goes wrong in module X, where
do I look for the problem?"
II. First, look in module X for the problem.
III. If it's caused immediately there, then look at all other modules that connect to X.
IV. Repeat this process until the source of the problem is located.
Clearly, this problem isolation process will be made more orderly, and potentially shorter if the
number of directly connected modules is limited
Techniques to increase coherence(Cohesion)
Generally, coupling measures are easier to pinpoint exactly.
Limiting the coupling between classes in turn increases cohesiveness, since
decoupling eliminates unnecessary items from classes.
To address cohesion directly means to design each class to represent a single, clearly
identifiable piece of data and/or encapsulate a single clearly identifiable area of
functionality.
To a large extent, the MVP design technique promotes cohesion, since it has well-
defined functionality for each category of design class.
Limiting the size of each individual scoping unit (class or function), per our design
and implementation conventions, is also a way to foster cohesion.
I.e., it's harder to do too much in a class or function if you can't do that much there in
the first place.
Summary
Coupling" and "cohesion" are terms used to denote module interconnectedness. Coupling refers to
how much inter-module connection exists in a design and Cohesion refers to how much intra-module
cohesiveness a design has.
In general, coupling should be minimized and cohesion should be maximized.
Specific measures of coupling are:
The number of classes that a given class inherits from;
The number of classes that a given class references as data members;
The number of methods that a given method calls;
The number of parameters that a given method has.
Specific measures of cohesion are:
The degree to which all methods in a class perform a logically-related aspect of system
functionality
The degree to which a method performs a single specific function
Questions:
1. Define the concept of cohesion and coupling.
2. State steps to minimize cohesion
3. State steps to maximize coupling
UNIT III
LESSON 39
STANDARD TEMPLATE LIBRARY(STL)
Objective
Intro to STL
Components of STL
Containers
Algorithms
Iterators
Sequential Containers
Introduction to the Standard Template Library
The Standard Template Library, or STL, is a C++ library of container classes, algorithms, and
iterators; it provides many of the basic algorithms and data structures of computer science. The STL
is a generic library, meaning that its components are heavily parameterized: almost every component
in the STL is a template. STL distinguishes general algorithms from the more specialized data and
methods encapsulated by ordinary abstract data types. In this way, complex and powerful algorithms
can be implemented independently of the data to which they are applied, allowing for generalization
and reuse of these algorithms. You should make sure that you understand how templates work in C+
+ before you use the STL.
The idea behind STL can easily be shown by the following consideration:
Imagine software components as a three-dimensional space. One dimension represents the data types
(int, double, char, ...), the second dimension represents the containers (array, linked-list, ...) and the
third dimension represents the algorithms (sort, merge, search, ...).
Figure: Component space
With this scenario given, i*j*k different versions of code have to be designed - a sort algorithm for
an array of int, the same sort algorithm for an array of double, a search algorithm for a linked-list of
double and so on. By using template functions that are parameterized by a data type, the i-axes can
be dropped and only j*k versions of code have to be designed, because there has to be only one
linked-list implementation which then can hold objects of any data-type. The next step is to make the
algorithms work on different containers - that means that a search algorithm should work on arrays
as well as on linked-lists, etc. Then, only j + k versions of code have to be created.
“Lets shortly summarize a few points about STL before we proceed further….”
1. Library of classes for use in manipulating data structures
2. High level code (most of the details hidden from view -- need only know the interface)
3. Safe reusable code:
1. Minimize need to manipulate pointers
2. Minimize dangers of reading past end of arrays
3. Minimize software development time for implementation of standard data structures
Templatized so can be used with variety of data types
Components of STL
The STL contains several components. But at its core there are three key components
They are
Containers
A container is an object that actually stores data. It is a way data is organized in memory.
The STL containers are implemented by template classes and therefore can be easily
customized to hold different types of data.
Containers are classes to contain data. Examples:
1. sequential containers
list
vector
deque
2. associative containers
set
map
multiset
multimap
3. container adaptors
stack
queue
priority_queue
Algorithms
Basic algorithms that can be used to manipulate the contents of containers. An algorithm
is a procedure that is used to process the data contained in the containers, The STL
includes many different kinds of algorithms to provide support to tasks such as
initializing, searching, copying, sorting, and merging. Algorithms are implemented by
template functions.
Examples:
a. copy()
b. sort()
Iterators
Iterators are classes to access elements in containers. Act like pointers, but
minimize the need to dereference. Minimize the need to implement loops for
accessing or outputting data
Containers and algorithms
Like many class libraries, the STL includes container classes: classes whose purpose is to contain
other objects.
The STL includes the classes vector, list, deque, set, multiset, map, multimap, hash_set,
hash_multiset, hash_map, and hash_multimap. Each of these classes is a template, and can be
instantiated to contain any type of object. You can, for example, use a vector<int> in much the
same way as you would use an ordinary C array, except that vector eliminates the chore of
managing dynamic memory allocation by hand.
vector<int> v(3); // Declare a vector of 3 elements.
v[0] = 7;
v[1] = v[0] + 3;
v[2] = v[0] + v[1]; // v[0] == 7, v[1] == 10, v[2] == 17
Characteristics of Containers
Here are some general characteristics of all containers:
1. Collections of items -- numbers, names, ordered pairs of items, etc.
2. Objects are stored in different ways depending on the container. Each container has its way
of storing objects.
Each container has methods (member functions) to do basic tasks.
The STL also includes a large collection of algorithms that manipulate the data stored in containers.
You can reverse the order of elements in a vector, for example, by using the reverse algorithm.
reverse(v.begin(), v.end()); // v[0] == 17, v[1] == 10, v[2] == 7
There are two important points to notice about this call to reverse. First, it is a global function, not
a member function. Second, it takes two arguments rather than one: it operates on a range of
elements, rather than on a container. In this particular case the range happens to be the entire
container v.
The reason for both of these facts is the same: reverse, like other STL algorithms, is decoupled
from the STL container classes. This means that reverse can be used not only to reverse elements in
vectors, but also to reverse elements in lists, and even elements in C arrays. The following program
is also valid.
double A[6] = { 1.2, 1.3, 1.4, 1.5, 1.6, 1.7 };
reverse(A, A + 6);
for (int i = 0; i < 6; ++i)
cout << "A[" << i << "] = " << A[i];
This example uses a range, just like the example of reversing a vector: the first argument to reverse
is a pointer to the beginning of the range, and the second argument points one element past the end
of the range. This range is denoted [A, A + 6); the asymmetrical notation is a reminder that the two
endpoints are different, that the first is the beginning of the range and the second is one past the end
of the range.
STL Example Code
Look at these sample code fragments, then read the discussion points afterwards.
Operations using a list class object
This example instantiates a list of int and then does some operations on it. A list class stores
data in the form of a linked list (Click here for a copy of the example code.):
#include < list > // std header file for STL list class
#include < algorithm > // std header file for STL algorithms
int main()
{
int num;
list < int > numbers; // declare an object of list class in STL
for( int i = 0; i < 10; i++ ) // read some numbers and insert in list:
{
cin >> num;
// insert the number before current beginning
numbers.insert( numbers.begin(), num );
}
numbers.sort(); // sort the numbers (low to high): member function
numbers.reverse(); // reverse the order: member function
numbers.remove(3); // remove all instances of the number 3
numbers.erase( ++numbers.begin() ); // erase the second element
ostream_iterator <int> output( cout, "\n" ); // output the list
copy( numbers.begin(), numbers.end(), output );
}
Points to note about this example:
1. You must include the header file list which declares the class template list.
2. You can instantiate a list object to any valid data type. The example object holds integers.
list is an example of a container class.
3. Just like any linked list, this one will add a node as needed when a new number is inserted.
4. insert()
1. This insert member function of the list class inserts the second argument before
the location specified by the first argument.
2. Its first argument is an iterator which for the list class is basically like a pointer to a
node in the list.
3. The list member function begin() returns an iterator (pointer) to the first node
5. Other member functions of the list class:
1. sort()
This is a member function of the list class. There is also a sort() non-member
algorithm that can be used.
2. reverse()
Reverse the current order of elements.
3. remove()
Delete all nodes storing instances of the argument passed in.
4. erase()
Delete the node occurring at the position indicated by the iterator argument. This
example deletes the first node after the beginning, i.e. the second node. Note the
difference between remove and erase. To delete all instances of an element, use
remove. To delete element at a given position, use erase.
6. Syntax of the iterator numbers.begin()
Notice that to get the next node after the beginning, I had to use the increment operator ++.
This gave a pointer to the second node in the list.
7. Output the list:
Output was accomplished using another iterator.
1. Instantiate an object of type ostream_iterator <int>.
2. The call to the ostream_iterator constructor says that cout will be the ostream
used and newlines \n will be the delimiters between successive outputs.
3. The ostream_iterator object is named output.
4. The STL algorithm function copy() writes all the list elements (from begin() to
end() to output.
Operations using a vector class object
A vector is a class that stores data using an array. This example instantiates an array of string
objects (Click here for a copy of the example code.).
#include < vector > // std header file for STL vector class
#include < algorithm > // std header file for STL algorithms
#include < string > // header for string class
int main()
{
vector < string > names; // declare an object of vector class in STL
char Name[10];
for( int i = 0; i < 10; i++ ) // read some names and insert in vector:
{
cin >> Name;
names.insert( names.begin(), Name );
}
names.erase( names.end() ); // erase the last string
sort( names.begin(), names.end() ); // sort the array: must use STL algorithm
for( unsigned i = 0; i < names.size(); i++ ) // output the array
cout << names[i] << endl;
}
Points to note about this example:
1. You must include the header file vector which declares the class template vector.
2. You can instantiate a vector object to any valid data type. The example object holds strings.
vector is another example of a container class.
3. vector stores objects in an array. But unlike arrays that you are familiar with, this one grows
or shrinks automatically as elements are added or removed.
4. Overloaded member subscript operator [ ]
Notice the subscript operator in the expression names[i]. A vector object is not an array,
but the overloaded subscript operator lets you have random access to the array of data
elements contained within it.
5. The vector member function end() returns an iterator (pointer) to the last element in the
array.
6. erase()
Delete the node occurring at the position indicated by the iterator argument. This example
deletes the last node.
7. size()
This is a member function that returns the number of elements in the class. size() is also a
member of the list class.
8. Note the member functions that are missing: Several member functions seen in the list
example are missing here:
9. remove
10. sort
11. reverse
This has to do with the different storage methods of a vector vs a list. Because vector
elements are stored in an array, the operations listed here cannot be implemented as
efficiently as they can be for data stored in linked lists.
12. STL Algorithms
We were able to sort the vector using the generic STL algorithm. The vector class does not
have its member sort().
13. Output of the array:
1. Notice we used a for loop together with overloaded index operator [ ] to output the
vector elements.
2. Output could also have been done using an ostream_iterator:
3. ostream_iterator<string> out( cout, "\n" );
4. copy( names.begin(), names.end(), out );
Discussion of these examples
These two examples have illustrated several points.
We saw examples of different types of objects:
1. container objects
1. list
2. vector
2. iterator objects
1. value returned by begin() and end()
2. ostream_iterator
3. We saw that list had different member functions than vector. This was related to the
different ways that list and vector store their data.
4. Thus there is an issue of which container object to use. Each has its good points and
drawbacks.
5. We saw two examples of STL algorithms:
6. copy()
7. sort()
Notice that the STL algorithm sort() is different from the list class member sort(). To
use it, we included the header algorithm.
Next we will discuss STL container objects with reference to these points.
Containers
These are classes for storing data. There are sequential containers that store data in the form of lists,
and associative containers.
Here are examples of methods common to all containers except stack, queue and
priority_queue:
1 Begin() find the first element.
2 Return an iterator (like a pointer) to that element
3 end() find the last element.
4 Return an iterator (like a pointer) to that element
5 size() return the number of elements currently container
6 erase() remove an element from the container at location
specified by iterator
7 operator=assign one container to another -- do memberwise
8 copy of objects stored in right side
9 operator== test for equality of two containers
10 operator!= test for inequality of two containers
Sequential Containers
These are containers that hold items in lists but are implemented in different ways. A list means a
collection of objects in which there is a first and a last object, and each object (except first and last)
has a predecessor and a successor. In other words, a list implies an ordering.
Now look at three types of classes implementing lists:
1. list class
1. Implemented as a doubly linked list (non-contiguous memory). This means each node
has a pointer forwards to the next node, and a pointer backwards to the previous node.
2. In addition to basic member functions above, also has these member functions:
3. sort() sort the elements in the list
4. reverse() reverse the current order of list
5. remove() delete all instances of argument object
6. Efficient insertion at beginning or end of list.
7. Linear time (O(N)) to access other elements of the list: must traverse the list.
8. List grows or shrinks automatically as elements are added or removed.
2. vector classes
1. Implemented as array (contiguous memory).
2. Efficient insertion at back of array: just add item to slot after current last.
3. Linear time(O(N)) to insert or remove element at front: must shift all the other array
elements to fill up empty hole.
4. Efficient access of indexed element: random access. This is accomplished by:
5. Overloaded subscript member operator [].
6. Grows or shrinks automatically as elements are added or removed.
3. deque class
1. Implemented in non-contiguous memory
2. Combine list's efficient insert/remove of front elements with vector's efficient
random access of indexed elements.
3. Has overloaded member subscript operator.
4. Grows or shrinks automatically as elements are added or removed.
The method of data storage in a container influences the efficiency of operations on the data. Here is
a table:
Operation vector deque list
--------- ------ ----- ----
Insert at beginning O(N) constant constant
Insert at end constant constant constant
Erase at beginning O(N) constant constant
Erase at end constant constant constant
Get first element constant constant constant
Get last element constant constant constant
Get middle element constant constant O(N)
Here O(N) means that the complexity of the operation depends upon the number of elements N stored
in the container object. It is a measure of the time needed to do the task. As N grows, then the time to
do the task grows roughly proportional to N.
Summary
A collection of generic classes and functions is called the Standard Template Library(STL). STL
components are part of C++ standard library.
The STL contains several components. But at its core there are three key components
They are
· Containers
· Algorithms.
· Iterators
The STL does, however, include several other types of components.
First, the STL includes several utilities: very basic concepts and functions that are used in
many different parts of the library. The concept Assignable, for example, describes types that
have assignment operators and copy constructors; almost all STL classes are models of
Assignable, and almost all STL algorithms require their arguments to be models of
Assignable.
Second, the STL includes some low-level mechanisms for allocating and deallocating
memory. Allocators are very specialized, and you can safely ignore them for almost all
purposes.
Finally, the STL includes a large collection of function objects, also known as functors. Just
as iterators are a generalization of pointers, function objects are a generalization of functions:
a function object is anything that you can call using the ordinary function call syntax. There
are several different concepts relating to function objects, including Unary Function (a
function object that takes a single argument, i.e. one that is called as f(x)) and Binary
Function (a function object that takes two arguments, i.e. one that is called as f(x, y)).
Function objects are an important part of generic programming because they allow
abstraction not only over the types of objects, but also over the operations that are being
performed.
Questions
1. what is STL How it is different from standard library
2. Discuss three types of containers
UNIT III
Lesson 40
Standard Template Library(STL) II
Objective
Algorithm
Iterator
Concept modeling
ALGORITHMS
Algorithms are functions that can be used generally across a variety of containers for processing
their contents. Although each container provides functions for its basic operations, STL provides
more than sixty standard algorithms to support more extended or complex operations. Standard
algorithms also permit us to work with two different types of containers
at the same time. Remember, STL algorithms are not member functions or friends of containers.
They are standalone template functions.
STL algorithms reinforce the philosophy of reusability. By using these algorithms, programmers can
save a lot of time and effort. To have access to the STL algorithms, we must include <algorithm> in
our program.
STL algorithms, based on the nature of operations they perform, may be categorized as
under:
. Retrieve or non-mutating algorithms . Mutating algorithms
. Sorting algorithms
. Set algorithms
. Relational algorithms
These algorithms are summarized in Tables.
STL also contains a few numeric algorithms under the header file <numeric>. They are listed
Non-mutating algorithms
Operations Description
Adjacent_find( ) Finds adjacent pair of objects that are equal
count( ) Counts occurrence of a value in a sequence
count_if( ) Counts number of elements that matches a predicate
equal( ) True if two ranges are the same
find( ) Finds first occurrence of a value in a sequence
for_each( ) Apply an operation to each element
search( ) Finds a subsequence within a sequence
Mutating algorithms
Operations Description
copy( ) Copies a sequence
fill() Fills a sequence with a specified value
generate( ) Replaces all elements with the result of an operation
iter_swap( ) Swaps elements pointed to by iter:'tors
remove( ) Deletes elements matching a predicate
replace( ) Replaces elements with a specified value
Sorting algorithm
Operations Description
binary _search( ) Conducts a binary search on an ordered sequence
equalrange( ) Finds a subrange of elements with a given value
merge( ) Merges two consecutive sorted sequences
pop_heap( ) Deletes the top element
push_heap() Adds an element to heap I
sort( ) Sorts a sequence
Iterators
Iterators behave like pointers and are used to access container elements. They are often used to
traverse from one element to another, a process known as iterating through the container.
There are five types of iterators as described
Iterator Access method Direction of movement I/O
capability
Remark
Input Linear Forward only Read only Cannot be saved
output Linear Forward only Write only Cannot be saved
Forward Linear Forward only Read / write Can be saved
Bidirectional Linear Forward & backward Read / write Can be saved
Random Random Forward & backward Read / write Can be saved
Different types of iterators must be used with the different types of containers. Note that only
sequence and associative containers are traversable with iterators.
In the example of reversing a C array, the arguments to reverse are clearly of type double*. What
are the arguments to reverse if you are reversing a vector, though, or a list? That is, what exactly
does reverse declare its arguments to be, and what exactly do v.begin() and v.end() return?
The answer is that the arguments to reverse are iterators, which are a generalization of pointers.
Pointers themselves are iterators, which is why it is possible to reverse the elements of a C array.
Similarly, vector declares the nested types iterator and const_iterator. In the example above,
the type returned by v.begin() and v.end() is vector<int>::iterator. There are also some
iterators, such as istream_iterator and ostream_iterator, that aren't associated with containers
at all.
Iterators are the mechanism that makes it possible to decouple algorithms from containers:
algorithms are templates, and are parameterized by the type of iterator, so they are not restricted to a
single type of container. Consider, for example, how to write an algorithm that performs linear
search through a range. This is the STL's find algorithm.
template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value)
{
while (first != last && *first != value) ++first;
return first;
}
Find takes three arguments: two iterators that define a range, and a value to search for in that range.
It examines each iterator in the range [first, last), proceeding from the beginning to the end,
and stops either when it finds an iterator that points to value or when it reaches the end of the range.
First and last are declared to be of type InputIterator, and InputIterator is a template
parameter. That is, there isn't actually any type called InputIterator: when you call find, the
compiler substitutes the actual type of the arguments for the formal type parameters InputIterator
and T. If the first two arguments to find are of type int* and the third is of type int, then it is as if
you had called the following function.
int* find(int* first, int* last, const int& value) {
while (first != last && *first != value) ++first;
return first;
}
Concepts and Modeling
One very important question to ask about any template function, not just about STL algorithms, is
what the set of types is that may correctly be substituted for the formal template parameters. Clearly,
for example, int* or double* may be substituted for find's formal template parameter Input
Iterator. Equally clearly, int or double may not: find uses the expression *first, and the
dereference operator makes no sense for an object of type int or of type double. The basic answer,
then, is that find implicitly defines a set of requirements on types, and that it may be instantiated
with any type that satisfies those requirements. Whatever type is substituted for Input Iterator
must provide certain operations: it must be possible to compare two objects of that type for equality,
it must be possible to increment an object of that type, it must be possible to dereference an object of
that type to obtain the object that it points to, and so on.
Find isn't the only STL algorithm that has such a set of requirements; the arguments to for_each and
count, and other algorithms, must satisfy the same requirements. These requirements are sufficiently
important that we give them a name: we call such a set of type requirements a concept, and we call
this particular concept Input Iterator. We say that a type conforms to a concept, or that it is a model
of a concept, if it satisfies all of those requirements. We say that int* is a model of Input Iterator
because int* provides all of the operations that are specified by the Input Iterator requirements.
Concepts are not a part of the C++ language; there is no way to declare a concept in a program, or to
declare that a particular type is a model of a concept. Nevertheless, concepts are an extremely
important part of the STL. Using concepts makes it possible to write programs that cleanly separate
interface from implementation: the author of find only has to consider the interface specified by the
concept Input Iterator, rather than the implementation of every possible type that conforms to that
concept. Similarly, if you want to use find, you need only to ensure that the arguments you pass to it
are models of Input Iterator. This is the reason why find and reverse can be used with lists,
vectors, C arrays, and many other types: programming in terms of concepts, rather than in terms of
specific types, makes it possible to reuse software components and to combine components together.
Refinement
Input Iterator is, in fact, a rather weak concept: that is, it imposes very few requirements. An Input
Iterator must support a subset of pointer arithmetic (it must be possible to increment an Input
Iterator using prefix and postfix operator++), but need not support all operations of pointer
arithmetic. This is sufficient for find, but some other algorithms require that their arguments satisfy
additional requirements. Reverse, for example, must be able to decrement its arguments as well as
increment them; it uses the expression --last. In terms of concepts, we say that reverse's
arguments must be models of Bidirectional Iterator rather than Input Iterator.
The Bidirectional Iterator concept is very similar to the Input Iterator concept: it simply imposes
some additional requirements. The types that are models of Bidirectional Iterator are a subset of
the types that are models of Input Iterator: every type that is a model of Bidirectional Iterator is
also a model of Input Iterator. Int*, for example, is both a model of Bidirectional Iterator and a
model of Input Iterator, but istream_iterator, is only a model of Input Iterator: it does not
conform to the more stringent Bidirectional Iterator requirements.
We describe the relationship between Input Iterator and Bidirectional Iterator by saying that
Bidirectional Iterator is a refinement of Input Iterator. Refinement of concepts is very much like
inheritance of C++ classes; the main reason we use a different word, instead of just calling it
"inheritance", is to emphasize that refinement applies to concepts rather than to actual types.
There are actually three more iterator concepts in addition to the two that we have already discussed:
the five iterator concepts are
Output Iterator,
Input Iterator,
Forward Iterator,
Bidirectional Iterator, and
Random Access Iterator;
Forward Iterator is a refinement of Input Iterator, Bidirectional Iterator is a refinement of
Forward Iterator, and Random Access Iterator is a refinement of Bidirectional Iterator.
(Output Iterator is related to the other four concepts, but it is not part of the hierarchy of
refinement: it is not a refinement of any of the other iterator concepts, and none of the other iterator
concepts are refinements of it.) The Iterator Overview has more information about iterators in
general.
Container classes, like iterators, are organized into a hierarchy of concepts. All containers are
models of the concept Container; more refined concepts, such as Sequence and Associative
Container, describe specific types of containers.
Other parts of the STL
If you understand algorithms, iterators, and containers, then you understand almost everything there
is to know about the STL. The STL does, however, include several other types of components.
First, the STL includes several utilities: very basic concepts and functions that are used in many
different parts of the library. The concept Assignable, for example, describes types that have
assignment operators and copy constructors; almost all STL classes are models of Assignable, and
almost all STL algorithms require their arguments to be models of Assignable.
Second, the STL includes some low-level mechanisms for allocating and deallocating memory.
Allocators are very specialized, and you can safely ignore them for almost all purposes.
Finally, the STL includes a large collection of function objects, also known as functors. Just as
iterators are a generalization of pointers, function objects are a generalization of functions: a
function object is anything that you can call using the ordinary function call syntax. There are
several different concepts relating to function objects, including Unary Function (a function object
that takes a single argument, i.e. one that is called as f(x)) and Binary Function (a function object
that takes two arguments, i.e. one that is called as f(x, y)). Function objects are an important part
of generic programming because they allow abstraction not only over the types of objects, but also
over the operations that are being performed.
STL include files STL is divided into the following header files in order to reduce compilation time.
algo.h includes all the algorithms
bool.h simulates bool
bvector.h bit_vector
deque.h deque
function.h operators, function objects and function adaptors
iterator.h iterator tags, stream iterators and iterator adaptors
list.h list
map.h map
multimap.h multimap
multiset.h multiset
pair.h pair
random.C random number generator. It should be compiled and
linked if random_shuffle is used.
set.h set
stack.h container adaptors
tempbuf.C an auxiliary buffer for get_temporary_buffer; it should be
compiled and linked if get_temporary_buffer, stable_partition,
inplace_merge or stable_sort are used.
tempbuf.h get_temporary_buffer
vector.h vector
(There are some other STL include files besides these but they are mainly for use with DOS and/or
Windows C++ compilers, for working with different memory models. They are not necessary for use
with the IBM xlC or Apogee apCC compilers.)
Summary
An algorithm is a procedure that is used to process the data contained in the containers, The STL
includes many different kinds of algorithms to provide support to tasks such as initializing,
searching, copying, sorting, and merging.
Algorithms are standalone functions that are used to carry out operations on the contents of
containers, such as sorting, searching, etc.
Iterators behave like pointers and are used to access container elements.
Iterators are the mechanism that makes it possible to decouple algorithms from containers:
algorithms are templates, and are parameterized by the type of iterator, so they are not restricted
to a single type of container.
Questions
1. what is an algorithm?. Discuss it in brief?
2. What is an Iterator? Discuss it in brief?
3. Write a function template palindrome that takes as a parameter a const vector and
returns true or false depending upon whether the vector does or does not read the
saim forwards as backwords
UNIT IV
LESSON 41
UNIFIED MODELING LANGUAGE (UML)
Objective
Concept of UML
UML Goals
UML Scope
UML Constituents
UML things
Overview of UML :
The Unified Modelling Language (UML) is a general-purpose visual modelling language. UMLis
used to' specify, visualize, construct, and document the artifacts of a software system. It captures
decisions and understanding about systems that is to be developed. It is commonly used to
understand. analyse, design, browse, configure, maintain, and control information about such
systems und~ development. It is specifically' designed for use with all development methods,
lifecycle stages.
application domains, and media. The modelling language is oriented to unify past experience about I
modelling techniques and to incorporate current software best practices into a standard approach.
UML covers semantic concepts, notation, and guidelines. It has different parts such as static,
dynamic, environmental, and organizational parts. It is intended to be supported by interactive visual
modelling CASE tools that have code generators and report writers. The UML specification does not
define a standard process however; it is intended to be useful with an iterative-development process.
It is intended to support most existing 00 development processes and methodologies. I
The UML captures information about the static system structure and dynamic behaviour of a system.
A system is modelled as a collection of discrete objects that interact with each other to perfonn work
that finally benefits an outside user. The static structure is used to define the kinds of
objectsimportant to a system and to its implementation, as well as the relationships among these
objects. The dynamic behaviour is used to define the history of objects over time and the
communications among objects to accomplish goals. Modelling a system from several separate but
related viewpoints allows it to be understood for different purposes.
The UML also includes organizational constructs for arranging models into packages that
permit
software teams to do following:
To partition large systems into workable pieces,
To understand and control dependencies among the packages
To manage the versioning of model units in a complex development environment.
It conains constructs for representing implementation decisions and for organizing run-time
elements into components.
UML is not a programming language. Some CASE Tools such as Rational Rose can provide code
generators from UML into a variety of programming languages, as well as construct reverse
engineered models from existing programs.
The UML is not a highly formal language intended for theorem proying. There are a number
of such languages, but they are not easy to understand or to use for most purposes.
The UML is a general-purpose modeling language. For specialized domains, such as GUI
layout, VLSI circuit design, or rule-based artificial intelligence, a more specialized tool with a
special language might be appropriate.
UML is a discrete modelling language. It is not intended to model continuous systems such as those
found in engineering and physics. UML is intended to be a universal general-purpose modelling
language for discrete systems such as those made of software, firmware, or digital logic, etc.
What is UML ? :
The Unified Modelling Language is a language that unifies the industry's best software engineering
practices for modelling OO systems. UML's architecture is shown in Fig.
The UML Scope,
unification
Process Programming Tool/Repository Language Specification
The Unified Modelling Language
The UML has following specifications:
UML is a language: It is not simply a notation for drawing diagrams, but a complete
language for capturing knowledge (semantics) about a subject and expressing knowledge
(syntax) regarding the subject for the purpose of communication.
UML applies to modelling and systems: Modelling involves a focus on understanding
(knowing) a subject (system) and capturing and being able to communicate this knowledge.
UML is the result of unifYing the information systems and technology industry's best
engineering
practices (principles, techniques, methods, and tools).
UML is used for specifying, visualizing, constructing and documenting systems.
UML is used for expressing the artifacts of system intensive process.
UML is based on the object-oriented paradigm.
UML is a modelling language for specifying, visualizing, constructing and documenting the
artifacts of a system-intensive process.
UML is an evolutionary general-purpose, broadly applicable, tool-supported, industry-
standardized modelling language.
UML applies to a multitude of different types of systems, domains and methods or process.
UML enables the capturing, communicating and leveraging of strategic, tactical, and
operational
knowledge to facilitate increasing value by increasing quality, reducing costs and reducing
time started the to -market while managing risks and being proactive about ever-increasing
change and complexity. .
UML was originally conceived by Rational Software Corporation and the Three Amigos as
follows :
Grady Booch's work has involved the ,use of Ada and the application of data
abstraction and information hiding with an emphasis on iterative software
development and software architecture. He has been influential in
disseminating object orientation. He is the inventor of the Booch method, as
expressed in his book Object-Oriented Analysis and Design.
James Rumbaugh's work has involved various topics concerning research and
development within the context of complex algorithms and data structures. He
co-authored the Object Modelling Technique (OMT) with Mike Blaha, Bill
Premerlani, Fred Eddy and Bill Lorensen.
Ivar Jacobson's work has involved the application of object orientation to the
context 0f business reengineering and the industrialization of software
development. He is often knoWl1 as the father of use cases. He is the inventor
of the Object-Oriented Software Engineering: A Use Case Driven Approach.
UML is supported by the UML Partners Consortium (Rational Software Corporation,
Microsoft Corporation, Hewlett-Packard Company, Oracle Corporation, Sterling Software,
MCI System house Corporation, Unisys Corporation, ICON Computing.
What Does Unified Mean? :
The word unified has the following relevant meanings for UML :
Across historical methods and notations: The UML combines the commonly accepted concepts
from many OO methods, selecting a clear definition for each concept, as well as a notation and
terminology. The UML can represent most existing models as well as or better than the original
methods can.
Across the development lifecycle : The UML is seamless from requirements to Implementation.
The same set of concepts and notation can be used in different phases of development and even
mixed within a single model. It is unnecessary to translate from one stage to another. This
seamlessness is critical for iterative, incremental development.
Across application domains: The UML is intended to model most application domains, with the
systems that are large, complex, real-time, distributed, data or computation intensive, among other
properties. There may be specialized areas in which a special-purpose language is more useful, but
UML is intended to be as good as or better than any other general-purpose modelling language for
most software application areas.
Across implementation languages and platforms: The UML is intended to be usable for systems
implemented in various implementation languages and platforms, including programming languages,
databases, 4GLs, organization documents, firmware and so on. The front-end aspect should be
identical or similar in all cases, while the backend work may differ somewhat for each medium.
Across development processes: The UML is a modelling language, and not a description of a
detailed development process. it is intended to be usable as the modelling language underlying most
existing or new development processes, just as a general purpose programming language can be used
in
many styles of programming. It is particularly intended to support the iterative, incremental style of
development that we recommend.
Across internal concepts: In constructing the UML metamodel, you can see, discover and represent
underlying relationships among various concepts, trying to capture model1ing concepts in a broad
way applicable to many known and unknown situations. This process led to a better understanding of
the concepts and a more general applicability of them. This was not the original purpose of the
unification work, but it was one of the most important results.
Scope and Goals of UML :
These were a number of goals behind the development of the UML. Some .of these goals are
as follows:
UML is a general-purpose modelling language that all modellers can use. It is intended to
address current software development issues, such as large scale, distribution, concurrency,
patterns, and team development.
UML is not intended to be a complete development method. It does not include a systematic
development process. '
A final goal of UML was to be as simple as possible while still being capable of modelling
the full range of practical systems that need to the built.
UML has different kinds of models; it is very difficult to master it in one day. It is more complicated
than the some of its antecedents, because it is intended to be more comprehensive. However, you do
not have to learn it al1 at once, any more than you would a programming language, an operating
system, or a complex user application.
UML Goals:
.
The goals of the UML are to
Be a ready-to-use expressive visual modelling language that is simple and extensible.
Have extensibility and specialization mechanisms for extending, rather than modifying, core
concepts.
Fonnalize a core set of concepts that constitute the object-oriented paradigm. Extensions
will not require reimplementation of the core object oriented paradigm (analysis and
design) concepts in order to be applicable to a broad set of applications. Instead,
practitioners can extend this core set of concepts based on varying interpretations without
having to be repeatedly redefined the fundamental concepts.
Allow adding new concepts and notation beyond the core.
Allow variant interpretations of existing concepts when there is no clear consensus.
Allow specialization of concepts, notation, and constraints for particular domains.
Be implementation independent (programming language).
Be process independent (development).
Encourage the growth of the object-oriented tools market.
Support higher-level concepts (collaborations, frameworks, patterns and components).
Address recurring architectural complexity problems (physical distribution and distributed
systems, concurrency and concurrent systems, replication, security, load balancing and fault
tolerance) using component technology, visual programming, patterns, and frameworks.
Be scalable.
Be widely applicable (general purpose and powerful) and usable (simple, widely accepted,
evolutionary). Integrate the best engineering practices.
The UML Scope:
The scope of the UML encompasses
Combines the concepts of Booch, OMT, and OOSE
Focusing on a standard modelling language (common notation) and not a standard process
Incorporating the object-oriented community's consensus on core modelling concepts
Providing sufficient notation to address contemporary modelling issues directly and
economically
Providing sufficient semantics to address the following issues directly and economically:
Contemporary modelling issues
Future modelling issues (specifically related to component technology, distributed
computing, frameworks and executability)
Model interchange among tools
Repository interfaces (to modelling artifacts) among tools
Providing extensibility mechanisms to address the following issues directly and economically
Current deviations within the object-oriented community
Extending the UML for individual projects
Future modelling approaches (on top of the UML)
What the UML Is Not:
The UML is not
A visual programming language, but a visual modelling language
o A programming language communicates im implementation or solution.
o A modelling language communicates a model (or conceptualisation or specification).
A tool or repository specification, but a modelling language specification
o A tool or repository specification specifies tools or repository's interface, storage, run-
time behaviour and so forth.
o A modelling language specification specifies modelling elements, notation, and usage
guidelines.
A process, but enables processes.
o A process provides guidance regarding the order of activities, specification of
artifacts to be developed, direction of individual developer and team tasks (or
activities) and monitoring and measuring criteria of project artifacts and activities.
o Processes are organization, culture, and domain specific and dependent.
o The UML enables and promotes (but does not require nor mandate) a use-case.driven,
architecture-centric, iterative, and incremental process that is object oriented and
component based.
UML Constituents:
UML consists of following things:
The UML Definition:
The UML is defined by a set of documents as shown in follow Fig. 2 from Rational Software
Corporation and the Object Management Group.
The UML Definition
The UML definition
Is expressed by the following documents (the UML-defining artifacts)
UML varients User-Defined UML Extensions
UML Extension for Objectory Process for Software Engineering UML Extension for Business modelling
UML Notation Guide :UML Semantics
Objects Constraint Language Specification
UML Semantics
UML Notation Guide
UML Introduction
UML Extension for the Objectory Process for Software Engineering
UML Extension for Business Modelling.
Uses the Object Constraint Language (OCL) defined by the Object Constraint Language
specification document.
May be obtained from Rational Software Corporation or the Object Management Group via
the World Wide Web (see the www.omg.org)
The UML Semantics Document:
The UML semantics document constitutes the single, common, definitive, formal, comprehensive
and precise specification of the UML (called the inside view). The UML semantics document.
Is primarily used by tool vendors; however, it maybe used by practitioners since it is the
definitive definition of the UML.
Specifies the UML has layered architecture, organization (using packages) and defined
modelling elements.
Includes the following inside-view information for a given UML package:
o Overview: General introduction
o Abstract syntax: Concept definitions, relationships, and constraints expressed using
the UML's graphical notation and English prose.
o Well-formed ness rules: Rules and constraints expressed using English prose and the
OCL. Semantics: Meanings expressed using English prose.
o Standard elements: Applicable standard extension mechanisms.
o Notes: Other commentary
Also contains appendices on the standard elements and the UML glossary.
Enables the development of complex systems, consistent usage of the UML, and tool interchange
The UML Notation Guide:
The UML Notation Guide constitutes the notational or visual representation of the UML and
provides examples (called the outside view). The UML Notation Guide
o Is primarily used by practitioners applying the UML
o Specifies the UML's diagrams and their modelling elements
o Includes the following outside-view information for each modelling element:
o Semantics: Summarizes the UML semantics.
o Notation (concrete syntax) : Explains the notational representation (forward mapping to
notation).
o Presentation options: Describe option in presenting modelling information.
o Style guidelines: Suggest stylistic markers and options.
o Examples: Provide notation samples.
o Mapping: Explains the mapping of the notation to the semantics document (reverse mapping
from notation).
o Enables the use of the UML
.
The UML Extension Documents:
The UML extension documents provide user-defined extensions (using extension mechanisms).
These documents
UML Introduction
o Extend the UML to the objectory process for software engineering.
o Extend the UML to business modelling.
A UML extension is a set of extensions (stereotypes, tagged values, and constraints) that extend,
customize, or tailor the UML for a specific domain or process.
A UML variant is a semantically well-defined language (expressed as a metamodel) based on (and
built on top of) the UML metamodeI. It specialized the UML but does not change the UML terms or
redefine their meanings.
The Object Constraint Language:
The Object Constraint Language (OCL) is a formal, easily readable and writable, non. programming,
implementation-independent language. The OCL
o Is used for expressing typed, pure, side-effect-free (precise and unambiguous) constraints and
Expressions
o Is used for attaching constraints and other expressions to the UML models and modelling
elements (or objects)
o Is used to specify the well-formedness rules of the UML within the UML semantics
document
o Is formally specified in the Object Constraint Language specification document, which
provides the following information: Connection with the UML semantics, basic values and
types, objects and properties, collection operations, predefined OCL types, and the grammar
for the OCL.
Scope and Purpose of UML as a Modelling Language:
The UML is a language for
. Visualizing
. Specifying
. Constructing
. Documenting
the artifacts of a software-intensive system.
The UML is a Language:
A language provides a vocabulary and the rules for combining words in that vocabulary for the
purpose of communication. A modelling language is a language whose vocabulary and rules focus
on the conceptual and physical representation of a system. A modelling language such as the UML is
thus a standard language for software blueprints.
Modelling yields an understanding of a system. No one model is ever sufficient. Rather, you often
need multiple models that are connected to one another in order to understand anything but the most
trivial system. For software-intensive systems, this requires a language that addresses the different
views of a system's architecture as it evolves throughout the software development life cycle.
The vocabulary and rules of a language such as the UML tell you how to create and read wellformed
models, but they do not tell you what models you should create and when you should create them.
That is the role of the software development process. A well-defined process will guide you in
deciding what artifacts to produce, what activities and what workers to use to create them and
manage them, and how to use those artifacts to-measure and control the project as a whole.
The UML is a Language for Visualizing:
For many programmers, the distance between thinking of an implementation and then pounding lout
in code is close to zero. You think it, you code it. In fact, some things are best cast directly in code.
Text is a wonderfully minimal and direct way to write expression and algorithms.
In such cases, the programmer is still doing some modelling, albeit entirely mentally. He or she )ay
even sketch out a few ideas on white board or on a napkin. However, there are several problems than
this. First, communicating those conceptual models to others is error-prone unless everyone
envolved speaks the same language. Typically, projects and organizations develop their own
language and it is difficult to understand what is going on if you are an outsider or new to the group.
Second,
there are some things about a software system you cannot understand unless you build models that
transcend the textual programming language. For example, the meaning of a class hierarchy can be
il1ferred, but not directly grasped, by starting at the. code for all the classes in the hierarchy.
Similarly,the physical distribution and possible migration of the objects in a Web-based system can
be inferred, but not directly grasped, by studying the system's code. Third, if the developer who cut
the code never l\\Tote down the models that are in his or her head, that information would be lost
forever or at best only partially recreatable from the implementation, once that developer moved on.
Writing models in the UML addresses the third issue: An explicit model facilitates
communication.
Some things are best modelled textually; others are best modelled graphically. Indeed, in all
interesting systems there are structures that transcend what can be represented in a programming
language. The UML is such a graphical language. This addresses the second problem described
earlier.
The UML is more than just a bunch of graphical symbols. Rather, behind each symbol in the
UML notation is a well-defined semantics. In this manner, one developer can write a model in the
UML and another developer or even another tool can interpret that model unambiguously. This
address the first issue described earlier.
The UML is a Language for Specifying:
In this context, specifying means building models that are precise, unambiguous and complete. In
particular, the UML address the specification of all the important analysis design and
implementation decisions that must be made in developing and deploying a software-intensive
system.
The UML is a Language for Constructing:
The UML is not a visual programming language but its models can be directly connected to a variety
of programming languages. This means that it is possible to map from a model in the UML to
programming language such as Java, C++, or Visual Basic, or even to tables in a relational database
or the persistent store of an object-oriented database. Things that are best expressed graphically are
done so graphically in the UML, whereas things that are best expressed textually are done so in the
programming language.
This mapping permits forward engineering: The generation of code from a UML model into' a
programming language. The reverse is also possible: You can reconstruct a. model from an
implementation back into the UML. Reverse engineering is not magic. Unless you encode that
information in the implementation, information is lost when moving forward from models to code.
Reverse engineering thus requires tool support with human intervention. Combining these two paths
of forward code generation and reverse engineering yields round-trip engineering, meaning the
ability to work in either a graphical or a textual view, while tools keep the two views consistent.
In addition to this direct mapping, the UML is sufficiently expressive and unambiguous to
permit the direct execution of models, the simulation of systems and the instrumentation of running
systems.
The UML is a Language for Documenting:
A healthy software organization produces all sorts of artifacts in addition to raw executable code.
These artifacts include (but are not limited to)
. Requirements . Architecture Design
. Source code . Project plans tests
. Prototypes . Releases
Depending on the development culture, some of these artifacts are treated more or less
formalIy than others. Such artifacts are not only the deliverables of a project, they are also critical in
controlling,. measuring and communicating about a system during its development and after its
deployment.
The UML addresses the documentation of a system's architecture and all of its details. The UML
also provides a language for expressing requirements and for tests. Finally, the UML provides a
language for modelling the activities of project planning and release management.
UML Applications:
The UML is intended primarily for software intensive systems. It has been used effectively for such
domains as :
Management information systems . Banking and financial services
Business Information systems . Telecommunications
Transportation . Defence/aerospace.
Retail . Medical electronics
Scientific . Distributed Web-based services
The UML is not limited to modelling software. In fact, it is expressive enough to model non--
software systems, such as workflow in the legal system, the structure, and behavior of a patient
health care system and the design of hardware.
.
.
.
A conceptual Model of UML :
To understand the UML, you need to form a conceptual model of the language, and this requires
learning three major elements: the UML's basic building blocks, the rules that dictate how those
building blocks may be put together and some common mechanisms that apply throughout the UML.
Once you have grasped these ideas, you will be able to read UML models and create some basic
ones. As you gain more experience in applying the UML, you can build on this conceptual model
using more advanced features of the language.
Building Blocks of the UML :
The vocabulary of the UML encompasses three kinds of building blocks:
UML Introduction
Things
Relationships
Diagrams
Things are the abstractions that are first-class citizens in a model; relationships tie these things
together; diagrams group interesting collections of things.
Things Included in the UML :
There are Four Kinds of Things in the UML as follows:
Structural things
Behavioural things
Grouping things
Annotational things
These things are the basic object-oriented building blocks of the UML. You can use them to
write well-formed models. .
Structural Things are the nouns of UML models. These are the mostly static parts of a model,
representing elements that are either conceptual or physical. In all, there are seven kinds of structural
things.
A class is a description of a set of objects that share the same attributes, operations, relationships,
and semantics. A class is used to implement one or more interfaces. Graphically a class is rendered
as a rectangle usually including its name, attributes, and operations. Class is shown in Fig.
Window
ongmsizeopen ( )close ( )move ( )display ( )Fig.: Classes
An interface is a collection of operations that specify a service of a class or component. An interface
describes the externally visible behavior of that element. An interface can represent the complete
behavior of a class or component or only a part of that behavior.
An interface defines a set of operation specifications (that is, their signatures) but never a set of
operation implementations. Graphically an interface is rendered as a circle together with its name.
An interface rarely stands alone. Rather it is typically attached to the class or component that realizes
the interface as shown in Fig
Ispelling
Fig. Interfaces
Collaboration defines an interaction and is a society of roles and other elements that work together to
provide some co-operative behavior that is bigger than the sum of all the elements.
Collaborations have structural as well as behavioural dimensions. A given class might participate in
several collaborations. These collaborations therefore represent the implementation of patterns that
make up a system. Graphically collaboration is rendered as an ellipse with dashed lines usually
including only its name as shown in Fig.
Fig. Collaborations
A use case is a description of set of sequence of actions that a system performs that yields an
observable result of value to a particular actor. A use case is used to structure the behavioral things
in a model. A use case is realized by collaboration. Graphically a use case is rendered as an ellipse
with solid lines usually including only its name as shown in Fig.
Fig.: Use Cases
The remaining three things active classes, components, and nodes are all class-like because they also
describe a set of objects that share the same attributes, operations, relationships, and semantics.
However, these three are different enough and are necessary for modeling certain aspects of an
object oriented system and so they warrant special treatment.
An active class is a class whose objects own one or more processes or threads and therefore can
initiate control activity.
An active class is just like a class except that its objects represent elements whose behavior is
concurrent with other elements. Graphically an active class is rendered just like a class but with
heavy lines usually including its name attributes and operations as shown in Fig.
Chain of resposibility
Place order
Fig.: Active Classes
The remaining two elements. component and nodes are also different. They represent physical things
whereas the previous five things represent conceptual or logical things.
A component is a physical and replaceable part of a system that conforms to and provides the
realization of a set of interfaces. In a system, you will encounter different kinds of deployment
components, such as COM+ components or Java Beans as well as components that are artifacts of
the development process such as source code files.
- A component typically represents the physical packaging' of other Wise logical elements such as
classes interfaces and collaborations. Graphically a. component is rendered as a rectangle with tabs
usually including only its name as shown in Fig. .
Fig : Components
Event Manager
Suspend()Flush()
orderform.java
A node is a physical element that exists at run time and represents a computational resource,
generally having at least some memory and often processing capability. A set of components may
reside on a node and may migrate from node to node. Graphically a node is rendered as a cube
usually including only its name as in shown Fig
Fig. Nodes
These seven elements classes, interfaces, collaborations, use cases, active classes, components
and nodes are the basic structural things that you can include in a UML model. There are also
variations
.on these seven such as actors signals and utilities (kinds of classes) processes and threads (kinds of
active classes) and applications documents files libraries pages and table (kinds of components).
Behavioral Things are the dynamic parts of UML models. These are the verbs of a model,
representing behavioral over time and space. In all, there are two primary kinds of behavioral
things.
An interaction is a behavior that comprises a set of messages exchange among a set of objects within
a particular context to accomplish a specific purpose. The behavior of a society of objects or have an
individual operation may specify with an interaction.
An interaction involves a number of other elements, including messages, action sequences (the
behaviour invoked by a message) and links (the connection between objects). Graphically a message
is rendered as a directed line usually including the name of its operation as shown in Fig.
server
display.
Fig. : Messages
A state machine is a behavior that specifies the sequences of states an object or an interaction goes
through during its lifetime in response to events, together with its responses to those events. The
behavior of individual class or a collaboration of classes may be specified with a state machine. A
state machine involves a number of other elements, including states, transitions (the flow from state
to state), events(things that trigger a transition) and activities (the response to a transition).
Graphically a state is rendered as a rounded rectangle, usually including its name and its substates, if
any as shown in Fig.
These two elements interactions and state machines are the basic behavioural things that you may
include in a UML model. Semantically, these elements are usually connected to various structural
elements, primarily classes, collaborations and objects.
Grouping Things are the organizational parts of UML models. A model can be decomposed into
these boxes. In all there is one primary kind of grouping thing namely packages.
States
A package is a general-purpose mechanism for organizing elements into groups. Structural things,
behavioural things and even other grouping things may be placed in a package. Unlike components,
(which exist at run time) a package is purely conceptual (meaning that it exists only at development
time). Graphically a package is rendered as a tabbed folder usually including only its name and
sometimes its contents as shown in Fig.
waiting
Fig.: Packages
Packages are the basic grouping things with which you can organize a UML model. There are also
variations such as frameworks models and subsystems (kinds of packages).
Annotational Things are the explanatory parts of UML models. These are the comments you may
apply to describe, illuminate, and remark about any element in a model. There is one primary kind of
annotational thing, called a note. A note is simply a symbol for rendering constraints and comments
attached to an element or a collection of elements. Graphically a note is rendered as a rectangle with
a dog-eared comer together with a textual or graphical comment as shown in Fig.
Fig. : Notes
This element is the one basic annotational thing you may include in a UML model. You will
typically use notes to adorn your diagrams with constraints or comments that are the best expressed
in informal or formal text. There are also variations on this element, such as requirements (which
specify some desired behavior from the perspective of outside of model).
Summary
The Unified Modelling Language (UML) is a general-purpose visual modelling language.
UML is used to' specify, visualize, construct, and document the artifacts of a software system
UML is not a programming language. Some CASE Tools such as Rational Rose can provide
code generators from UML into a variety of programming languages, as well as construct
reverse engineered models from existing programs.
The UML is a Language: Who provides a vocabulary and the rules for combining words in
that vocabulary for the purpose of communication. A modelling language is a language
whose vocabulary and rules focus on the conceptual and physical representation of a system.
A modelling language such as the UML is thus a standard language for software blueprints.
There are Four Kinds of Things in the UML as follows:
Structural things
Behavioural things
Grouping things
Annotational things
Question
1. Explain the concept of UML?
2. Explain Its scope and Goal
3. Discuss UML things
UNIT V
LESSON 42
UML IIObjective
UML diagrams
UML relationships
Object Oriented Software Engineering
UML Diagrams
This part introduces you to the 9 standard diagrams in the UML 1.4 specification. These diagrams
can be divided into two groups: Structural diagrams, which model the organization of the solution,
and Behavioral diagrams, which model the functionality of the solution.
Structural Diagrams
Class Diagram
Object Diagram
Component Diagram
Deployment Diagram
Behavioral Diagrams
Use Case Diagram
Sequence Diagram
Collaboration Diagram
Statechart Diagram
Activity Diagram
Class Diagrams
Class diagrams identify the class structure of a system, including the properties and methods of each
class. Also depicted are the various relationships that can exist between classes, such as an
inheritance relationship. The Class diagram is one of the most widely used diagrams from the UML
specification. Part of the popularity of Class diagrams stems from the fact that many CASE tools,
such as Rational XDE, will auto-generate code in a variety of languages, including Java, C++, and
C#, from these models. These tools can synchronize models and code, reducing your workload, and
can also generate Class diagrams from object-oriented code, for those "code-then-design"
maintenance projects.
Notation
UML Notation
There are many different types of UML notation. For this short presentation, a few types of notation
will be covered. For a more complete description of the UML notation, you can refer to the UML
1.1 Notation Guide. When beginning to use the UML, it is helpful to start with some basic notation
(e.g., class diagrams) and, then, as you become more proficient, advanced UML notation can be
used.
The elements on a Class diagram are classes and the relationships between them Class
Classes are the building blocks in object-oriented programming. A Class is depicted using a
rectangle divided into three sections. The top section is the name of the Class. The middle section
defines the properties of the Class. The bottom section lists the methods of the class.
Association An Association is a generic relationship between two classes, and is modeled by a line
connecting the two classes. This line can be qualified with the type of relationship, and can also
feature multiplicity rules (eg. one-to-one, one-to-many, many-to-many) for the relationship.
Composition If a class cannot exist by itself, and instead must be a member of another class, then
that class has a Composition relationship with the containing class. A Composition relationship is
indicated by a line with a filled diamond.
Dependency When a class uses another class, perhaps as a member variable or a parameter, and so
"depends" on that class, a Dependency relationship is formed. A Dependency relationship is
indicated by a dotted arrow.
Aggregation Aggregations indicate a whole-part relationship, and are known as "has-a" relationships. An Aggregation relationship is indicated by a line with a hollow diamond.
Generalization A Generalization relationship is the equivalent of an inheritance relationship in
object-oriented terms (an "is-a" relationship). A Generalization relationship is indicated by an arrow
with a hollow arrowhead pointing to the base, or "parent", class.
Consider the example of a veterinary system. Animals served, such as dogs and birds, are tracked along with their owners. The following diagram models a potential solution. Since dogs and birds are "a kind of" animal, we use a Generalization relationship.
To validate your model, you can apply real-world data into instances of the classes. In fact, there is a
diagram for precisely this task, the Object Diagram.
Class Diagram
Class diagrams represent the static structure of the classes and their relationships (e.g., inheritance, aggregation) in a system. A class icon is divided into three components—class name, attributes, and operations.
The access modifier symbols +, -, and # correspond respectively to public, private, and protected
access modifiers.
Realizes relationship from a class to an interface indicates that the class implements the operations
specified in the interface.
Associations represent relationships between instances of classes. Each association has two roles;
each role is a direction on the association.
A role has multiplicity (an indication of how many objects may participate in a given relationship).
Examples of multiplicity indicators are: 1 (Exactly one), * (0 to any positive integer), 1..* (1 to any
positive integer), 0..1 (0 or 1).
Constraint specifies conditions among model elements that must be maintained as true. Constraints
are shown using text enclosed in braces.
Generalization relationship is an association with a small triangle next to the class being inherited
from whereas an aggregation relationship is an association with a diamond next to the class
representing the aggregate.
Class diagrams can be used to document a Business Object Model and are widely used in both high-
level and low-level design documents.
From a Java perspective, it may not be effective to include each and every operation and attribute of
a class in a class diagram because this leads to maintenance issues (e.g., if a method or attribute
changes in the code then the model needs to be updated); rather, javadoc can be used to document an
implementation.
To maintain consistency with Java coding style, class names should begin with an uppercase letter
while operations and attributes should begin with a lowercase letter.
Generalization relationships can be mapped to the Java extends relationship while the realizes
relationship can be mapped to the Java implements relationship.
Package Diagram
Package diagrams provide a mechanism for dividing and grouping model elements (e.g., classes, use
cases). In UML, a package is represented as a folder.
In effect, a package provides a namespace such that two different elements in two different packages
can have the same name.
Packages may be nested within other packages.
Dependencies between two packages reflect dependencies between any two classes in the packages.
For example, if a class in Package A uses the services of a class in Package B, Package A is
dependent on Package B. An important design consideration is the minimization of dependencies
between packages.
Package diagrams can be used in a high-level design or architecture document to describe a system’s
overall structure, can support project planning and also be used as a unit to perform testing.
A package can be considered logically equivalent to a Java package and dependencies between
packages can be mapped to Java import statements.
Use Case Diagram
Use cases are used to obtain system requirements from a user's perspective. A use case can be
described as a interaction that a user has with a system to achieve a goal. It is helpful to provide a
template that can be used to document use cases. Note that a use case template is not part of the
UML notation A typical use case can be documented using the following template:
A use case diagram provides an overview of the system's use cases and their actors; it places use
cases in context. In UML, an actor is represented as a stickman while a use case is represented as an
oval.
An actor is a role that a user plays with respect to the system.
Two types of relationships are used in use case diagrams.
The extends relationship is used when one use case is similar to another use case but does a bit more
or to describe optional behavior (e.g., forward a mail message).
The uses relationship occurs when you have common behavior that exists in multiple use cases that
can be factored out into a separate use case (e.g., login use case). Note that actors have relationships
to use cases that are being extended whereas there is often no actor associated with a common use
case.
Use case diagrams can be used in product specifications, software architecture documents, and
system test documents to provide an overview of the system requirements.
Use cases can specify prioritization that can support a phased delivery of a system.
Use cases can also be used to develop test plans and user guides.
Interaction Diagrams: Sequence and Collaboration
Interaction diagrams show how objects interact with one another. There are two types of interaction
diagrams: Collaboration Diagram and Sequence Diagram.
Collaboration diagrams can be used to show how objects in a system interact over multiple use
cases. Collaboration diagrams are helpful during the exploratory phases of a development process
(i.e., trying to search for objects and their relationships). Since there is no explicit representation of
time in Collaboration Diagrams, the messages are numbered to denote the sending order.
A Sequence diagram is typically used to show object interactions in a single use case and it is easier
to see the order in which activities occur. The emphasis of sequence diagrams is on the order of
message invocation. The vertical axis of a sequence diagram represents time whereas the horizontal
axis represents objects.
Interaction diagrams can be used during the high-level design (e.g., for business object model
development) as well as for low-level design activities (e.g., developing an implementation for a use
case). Interaction diagrams are helpful for showing the collaborations between objects but fall short
in terms of a complete definition of the behavior.
Activity Diagrams
Activity diagrams show behavior with control structure. Activity diagrams can be used to show
behaviors over many use case, model business workflows, or describe complicated methods.
Activities in a diagram may or may not correspond to methods.
Specific notation found in this type of diagram includes guards which are logical expressions that
evaluate to true or false.
A synchronization bar indicates that the outbound trigger occurs only after all inbound triggers have occurred.
Swimlanes (using a swimming pool analogy) allow you to vertically partition an activity diagram so
that the activities in each lane represent the responsibilities of a particular class or department.
Activity diagrams are helpful early in the modeling of a process to help you understand the overall
process. Useful when you want to show parallel processes or for multithreaded programs.
Disadvantage of activity diagrams is that they do not make explicit which objects execute which
activities, and the way that the messaging works between them.
Relationships in UML
Dependency
The most general is called a dependency relationship and applies uniformly to all the model
elements. Association and generalization apply to all types, in particular classes and use cases. The
last two relationships – transitions and links – apply to certain model elements pertaining to
behavior.
This section is limited to the description of static relationships between classes, shown in the
diagram below. Links and transitions are discussed later on in this chapter.
Simplified metamodelà ‚ — representation of relationships between classes
Association
An association specifies a bi-directional, semantic connection between types. An association has at
least two roles, which describe the part played by the types that participate in the association.
Each role comprises the following attributes:
Multiplicity – specifies the number of instances that participate in the relationship
Navigability – specifies if links (association instances) may be navigated along in the direction of
the role being considered.
Aggregation indicator – specifies if the instances of the type associated to the role correspond to
the whole in a (whole, part) relationship. Only one of the roles of an association may have an
aggregation indicator set to True. If the multiplicity is larger than 1, several instances play the role
of the whole and share the parts.
Changeability – specifies if the semantics of the association are preserved when an instance of the
type that participates in the role is replaced by another instance
Ordering – applies when the multiplicity value is greater than 1, to mean that the instances are
ordered
An association role may also include a set of attributes whose values implement a partition of the set
of objects of the associated class.
Generalization
Generalization specifies a classification relationship in which an instance of a subtype may be
substituted for an instance of a supertype. A supertype may have several subtypes, and a subtype
may have several supertypes.
Simplified metamodel—representation of the generalization relationship and of
elements prone to generalization.
Any element that may be generalized includes the following Boolean attributes:
Abstract – the value True specifies that the element cannot be instantiated directly
Leaf – the value True specifies that the element may not have subtypes
Root – the value True specifies that the element may not have supertypes
UML defines three kinds of generalizable elements:
Stereotypes allow the classification of a model element and, eventually, the definition of a particular
graphical representation. A stereotype cannot have a subtype.
Packages provide a general mechanism for grouping elements (both model and visual elements). A
package cannot have supertypes.
Types specify a definition domain and the operations applicable to that domain.
Dependency
Dependency is a unidirectional usage relationship between elements (both model and visual). The
dependency relationship connects elements within the same model.
Simplified metamodel—representation of dependency relationships
UML also provides a 'trace' relationship between elements that belong to different models. Notably,
the trace may be used to represent the history of current constructions in various models. This trace
relationship is a stereotyped dependency relationship.
Simplified metamodel—the trace relationship is a stereotyped dependency relationship.
UML is a consistent language for denoting the artifacts of a system. System architects can use it to
specify, visualize, construct and document designs. The language is most commonly used to denote
the artifacts of software systems, as a part of the software development process.
The Unified Modeling Language includes:
Model elements, that capture the fundamental modeling concepts and semantics.
A notation, for visual rendering of model elements.
Rules, that describes idioms of usage.
It also provides extensibility and specialization mechanisms to extend the core concepts.
UML does not provide, define nor dictate:
A Programming Language. UML has a semantics model that maps well to a family of OO
languages, but in itself does not require the use of a specific language tools. UML neither specifies
the design of CASE tools, nor specifies the use of them. However, it is natural to expect that CASE
tools supporting UML follows the UML semantics closely.
A development process. Defining a standard process was not a goal of UML, and UML has
intentionally been made process independent.
Object oriented software engineering
Object-Oriented Concepts And Princlples
we live in a world of objects. these objects exist in nature, in humanmade entities, in business, and in
the products that we use. they can be categorized, described, organized, combined, manipulated, and
created. therefore, it is no surprise that an object-oriented view would be proposed for the creation of
computer software-an abstraction that enables us to model the world in ways that help us to better
understand and navigate it.
an object-oriented approach to the development of software was first proposed in the late 1960s.
however, it took almost 20 years for object technologies to become widely used. throughout the
1990s, object-oriented software engineering became the paradigm of choice for many software
product builders and a growing number of information systems and engineering professionals. as
time passes, object technologies are replacing classical software development approaches. an
important question is why?
the answer (like many answers to questions about software engineering) is not a simple one. some
people would argue that software professionals simply yearned for a "new" approach, but that view
is overly simplistic. object technologies do lead to a number of inherent benefits that provide
advantage at both the management and technical levels.
what is it? there are many ways to look at a problem to be
solved using a software-based
solution. One widely used approach to problem solving takes an object-oriented viewpoint. The
problem domain is characterized as a set of objects that have specific attributes and behaviors. The
objects are manipulated with a collection of func
tions (called methods, operations, or services) and communicate with one another through a mes-
saging protocol. Objects are categorized into classes and subclasses.
Who does It? The definition of objects encompasses a description of attributes, behaviors,
operations, and messages. This activity is performed by a sOftware engineer.
Why is it important? An object encapsulates both data and the processing that is applied to the data.
This important characteristic enables classes of objects to be built and inherently leads to libraries of
reusable classes and objects. Because reuse is a critically important attribute of modern software
engineering, the object-oriented paradigm is attractive to many software development organizations.
In addition, the software components derived using the object-oriented paradigm exhibit design
characteristics (e.g., functional independence, information hiding) that are associated with high-
quality software.
What are the steps? Object-orientect software engineering follows the same steps as conventional
approaches. Analysis identifies objects and classesdomain; design provides the architecture,
interface, and component-level detail; that are relevant to the problem implementation (using an
object-oriented language) transforms design into code; and testing exercises the object-oriented
architecture, interfaces and components.
What is the work product? A set of object oriented models is produced. These models describe the
requirements, design. code. and test process a system or product.
How do I ensure that I've done It right? At each stage, object-oriented work products are reviewed
for clarity, correctness, completeness. and corm tency with customer requirements and with one
another.
Object technologies lead to reuse, and reuse (of program components) leads to faster software
development and higher-quality programs. Object-oriented software is easier to maintain because its
structure is inherently decoupled. This leads to fewer side effects when changes have to be made and
less frustration for the software engineer and the customer. In addition, object-oriented systems are
easier to adapt and easier to scale (ie., large systems can be created by assembling reusable sub sys
tems).
Three important concepts differentiate the OO approach from conventional software engineering.
Encapsulation packages data and the operation that manipulate the data into single
named object.
Inheritance enables the attribute and operations to be inherited by all subclasses and
the objects that are instantiated from them.
Polymorphism enables a number of different operations to have the same name,
reducing the number of lines of code required to implement a system and facilitating
changes when they are made.
Object oriented product and systems are engineered using and evolutionary model, sometimes called
a recursive/ parallel model. OO software evolves iteratively and must be managed with the
recognition that the final product will be developed over a series of increments
Summary
UML is a modeling language for specifying, visualizing, constructing, and documenting the
artifacts of a system-intensive process.
UML represents a unification of the concepts and notations of Booch, Rumbaugh, and
Jacobson.
Notation plays an important role in modeling and the goal of the UML is to become a
universal notation for creating models of object-oriented (OO) software.
UML gives 9 standard diagrams These diagrams can be divided into two groups: Structural
diagrams, which model the organization of the solution, and Behavioral diagrams, which
model the functionality of the solution.
Questions
1. What is UML?
2. Explain different types of UML diagram. Give details of different notatios
used .
3. Discuss concept OO software Engineering
UNIT V
Lession 43
Group Discussion on the concept of analysis ans design method and
UML concepts in Detail.
References :
1. Object Oriented Progarmming With C++ - E Balguruswami
2. Let’s C++ - Y. Kanetkar
3. Object Oriented Modelling & Design- S.D. Joshi
4. C++ How To Program – Deitel & Deitel