0% found this document useful (0 votes)
548 views389 pages

C++ Final Class Concepts Explained

The document outlines topics to be covered over 8 days of training on C++. Day 1 covers basic OOP concepts like classes, objects, functions and constructors. Day 2 covers operator overloading, inheritance and containership. Day 3 covers I/O streams and file handling. Day 4 covers templates and exception handling. Days 5-6 cover polymorphism concepts like virtual functions and RTTI. Day 7 covers debugging and Day 8 covers STL and generic programming.

Uploaded by

Shaan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
548 views389 pages

C++ Final Class Concepts Explained

The document outlines topics to be covered over 8 days of training on C++. Day 1 covers basic OOP concepts like classes, objects, functions and constructors. Day 2 covers operator overloading, inheritance and containership. Day 3 covers I/O streams and file handling. Day 4 covers templates and exception handling. Days 5-6 cover polymorphism concepts like virtual functions and RTTI. Day 7 covers debugging and Day 8 covers STL and generic programming.

Uploaded by

Shaan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd

Day No

Topics to be covered
Day#1 Basic concepts of OOPS, class and object
definition
Naming conventions
Inline functions
Scope resolution operator
Default arguments
Function overloading
Constructors and Destructors
Static members
Type conversions
Friends
C++

Horizon

Day No

Topics to be covered

Day#2

Operator Overloading
The string class
Inheritance
Access modifiers
Multiple inheritance
Containership

Day#3
Formatting and manipulators
I/O files and streams
Day#4 Template functions and classes
Exception Handling
C++

Horizon

Day No

Topics to be covered

Day#5

Virtual functions and dynamic polymorphism


Vtables

Day#6

Day#7

The debugger

Day#8

STL and Generic Programming

C++

Interfaces
RTTI
Namespaces
Memory Management

Horizon

Concepts of OOPS

C++

Horizon

A PIE
Abstraction :
The ability for a program to ignore some aspects of the information that it
is manipulating, i.e. the ability to focus on the essential.
It is the process of creating a category ( class ) by identifying those features
of the category which give a nearly complete picture of the class as is
required by the programmer.

Encapsulation :
It is the process of encapsulating all the identified data and functional
properties for the category as a single entity, called class.
It ensures that users of an object cannot change the internal state of the
object in unexpected ways; only the object's own internal methods are
allowed to access its state. Each object exposes an interface that specifies
how other objects may interact with it.
C++

Horizon

Polymorphism :
It gives the ability to take more than one forms. That is, an operation may
exhibit different behavior in different instances.
Object-oriented languages can make message sends; the specific method
which responds to a message send depends on what specific object the
message is sent to. This gains polymorphism, because a single variable in
the program text can hold different kinds of objects as the program runs,
and thus the same program text can invoke different methods at different
times in the same execution.

Inheritance :
It is the process by which an object of a particular category acquires the
properties of another category thus generating a hierarchical classification
of objects.
It organizes and facilitates polymorphism and encapsulation by permitting
objects to be defined and created that are specialized types of alreadyexisting objects - these can share (and extend) their behavior without
having to reimplement that behavior.
C++

Horizon

OBJECTS AND CLASSES


Objects :
An object is a software bundle of related variables and methods.
Real world objects share two characteristics: they all have state and
behavior.
Example :
Dogs have state (name, color, breed, hungry) and behavior (barking,
fetching, and wagging tail).
Bicycles have state (current gear, current pedal cadence, two wheels,
number of gears) and behavior (braking, accelerating, slowing down,
changing gears).
Software objects are modeled after real-world objects - they too have
state and behavior.
A software object maintains its state in one or more variables - an item
of data named by an identifier.
A software object implements its behavior with methods - a function
(subroutine) associated with an object.
C++

Horizon

The object's variables make up the center, or nucleus, of the object.


Methods surround and hide the object's nucleus from other objects in
the program.
Packaging an object's variables within the protective custody of its
methods is called encapsulation
This conceptual picture of an object a nucleus of variables packaged
within a protective membrane of methods is an ideal representation
of an object and is the ideal that designers of object-oriented systems
strive for.
Often an object may wish to expose some of its variables or hide some
of its methods. An object can specify one of four access levels for each
of its variables and methods. The access level determines which other
objects and classes can access that variable or method.

C++

Horizon

Encapsulating related variables and methods into a neat software bundle is a


simple yet powerful idea that provides two primary benefits :
Modularity: The source code for an object can be written and maintained
independently of the source code for other objects. Also, an object can be
easily passed around in the system.
You can give your bicycle to someone else, and it will still work.
Information hiding: An object has a public interface that other objects can
use to communicate with it. The object can maintain private information and
methods that can be changed at any time without affecting the other objects
that depend on it.
You don't need to understand the gear mechanism on your bike to use it.

C++

Horizon

Classes :
A class is a blueprint or prototype that defines the variables and the methods
common to all objects of a certain kind.
In the real world, you often have many objects of the same kind. For
example, your bicycle is just one of many bicycles in the world. Using
object-oriented terminology, we say that your bicycle object is an instance
of the class of objects known as bicycles. Bicycles have some state (current
gear, current cadence, two wheels) and behavior (change gears, brake) in
common. However, each bicycle's state is independent of and can be
different from that of other bicycles.
When building bicycles, manufacturers take advantage of the fact that
bicycles share characteristics, building many bicycles from the same
blueprint. It would be very inefficient to produce a new blueprint for every
individual bicycle manufactured.
In object-oriented software, it's also possible to have many objects of the
same kind that share characteristics: rectangles, employee records, video
clips, and so on. Like the bicycle manufacturers, you can take advantage of
the fact that objects of the same kind are similar and you can create a
blueprint for those objects.
A software blueprint for objects is called a class.
C++

Horizon

10

RULES OF THUMB
for class designing
If you can think of it as a separate idea, make it a class.
If you can think of it as a separate entity, make it an object
of some class.
If two classes have something significant in common, make
that commonality a base class.

C++

Horizon

11

MESSAGES
An object is a software bundle of related variables and methods.
Software objects interact and communicate with each other using
messages.
A single object alone is generally not very useful. Instead, an object usually
appears as a component of a larger program or application that contains
many other objects.
Your bicycle hanging from a hook in the garage is just a bunch of metal
and rubber; by itself, the bicycle is incapable of any activity. The bicycle is
useful only when another object (you) interacts with it (pedal).
Software objects interact and communicate with each other by sending
messages to each other. When object A wants object B to perform one of
B's methods, object A sends a message to object B.

C++

Horizon

12

Sometimes, the receiving object needs more information so that it knows


exactly what to do; for example, when you want to change gears on your
bicycle, you have to indicate which gear you want.
This information is passed along with the message as parameters.
A message has three parts :
The object to which the message is addressed
The name of the method to perform
Any parameters needed by the method
An object's behavior is expressed through its methods, so (aside from direct
variable access) message passing supports all possible interactions between
objects.
Messages provide important benefits - Objects don't need to be in the same
process or even on the same machine to send and receive messages back and
forth to each other.

C++

Horizon

13

OOAD

C++

Horizon

14

The starting point for object-oriented analysis is to identify


candidate objects and their relationships. In fact, this is the be-all
and end-all of object-oriented analysis.
The first stage can be a simple brain-storming of the possible
objects. One method is to go through all the nouns in any
documentation about the world you are analyzing, and
considering these as candidate objects.
Let us suppose that we are analyzing a system for a motor
museum. The system is to produce a multi-media guide to the
museum.
A preliminary list of objects might be:
car, bus, vehicle, number plate, exhibit, manufacturer, date of
manufacture, value, position, weight, size, photograph, tools,
shop, garage, ticket, owner, history
C++

Horizon

15

Removing synonyms and/or generalizing


The first stage is to try and group together items which are either
just different names for the same thing, or whether there is a
common generalization. The obvious thing above is to examine
the following group :
car, bus, vehicle, number plate, exhibit, photograph, tools, garage
It would seem that these could all be grouped together under the
object exhibit. In the museum the behavior of cars, photographs,
and garages are not radically different, so we can group them
together. We can differentiate between the individual objects on
the basis of an attribute, say type.
We are then left with the list of candidate objects:
exhibit, manufacturer, date of manufacture, value, position,
weight, size, shop, ticket, owner, history
C++

Horizon

16

Look for attributes


Attributes are themselves objects, but with trivial behavior essentially all you do is record their value. Considering the above
list, the following are probably attributes of exhibit:
date of manufacture, value, position, weight, size, owner
And we are left with the candidate objects:
exhibit, manufacturer, shop, ticket, history
We might have considered manufacturer as an attribute, but it
may be useful to separate out manufacturer information later in
the design. So we keep it for the time-being. The time to fold it in
as an attribute is when we find it has no discernible behavior of
its own.

C++

Horizon

17

Irrelevant objects
Sometimes an object is irrelevant.
Here the ticket object may be very relevant for a sales desk
system, but not for a multi-media system. Likewise, the shop is
irrelevant.
So we strike these out and we are left with the following objects.
exhibit, manufacturer, history
We have these objects potentially linked in the following way.

C++

Horizon

18

The process of development


The approach to development recommended here is an iterative one.
It involves repeated refinement of the object model. The process
needs to be controlled by an appropriate project management
process, involving reviews and check pointing.

C++

Horizon

19

Naming Convention
This is a set of rules for choosing the character sequence to be
used for identifiers which denote variables, types and functions
etc. in source code and documentation.
The reasons for using a naming convention (as opposed to
allowing programmers to choose any character sequence) include
the following :
to reduce the effort needed to read and understand source code
to enhance source code appearance (for example, by disallowing
overly long names or abbreviations)

C++

Horizon

20

Some of the potential benefits that can be obtained by adopting a naming


convention include the following :
to provide additional information about the use to which an identifier is put
to help promote consistency within a development team
to enhance clarity in cases of potential ambiguity;
to enhance the aesthetic and professional appearance of work product (for
example, by disallowing overly long names, comical or "cute" names, or
abbreviations);
to provide meaningful data to be used in project handovers which require
submission of program source code and all relevant documentation and
to provide better understanding in case of code reuse after a long interval of
time - well-chosen identifiers make it significantly easier for subsequent
generations of analysts and developers to understand what the system is doing
and how to fix or extend the source code for new business needs.
C++

Horizon

21

The two most common conventions are :


The CamelCase notation (originally known as medial capitals)
The Hungarian Notation (which encodes either the purpose - "Apps
Hungarian, or the type - "Systems Hungarian" of a variable in its name.)

C++

Horizon

22

The CamelCase :
This is the practice of writing compound words or phrases in which the elements
are joined without spaces, with each element's initial letter capitalized within the
compound and the first letter is either upper or lower case - as in "LaBelle",
BackColor or "iPod".
The name comes from the uppercase "bumps" in the middle of the compound
word, suggestive of the humps of a camel.
The practice is known by many other names. In computer programming, it is
called Pascal case if the first letter is capitalized, and camel case otherwise.
The first letter of a camel-case compound may or may not be capitalized.
Camel case is by no means universal in computing. In some programming
languages, notably Lisp and Forth, compound names are usually separated by
hyphens.
The use of medial caps for compound identifiers is recommended by the coding
style guidelines of many organizations or software projects.
For some languages (such as Mesa, Pascal, Modula, Java and Microsoft's .NET)
this practice is recommended by the language developers or by authoritative
manuals
and has therefore become part
of the language's "culture".
C++
Horizon
23

The Hungarian Notation (original developer, Charles Simonyi) :


Hungarian notation is an identifier naming convention in which the name of a
variable or function indicates its type or intended use.
There are two types of Hungarian notation :
Systems Hungarian notation
and
Apps Hungarian notation.
The two notations differ is in the purpose of the prefixes.
Hungarian notation was designed to be language-independent, and found its first
major use with the BCPL programming language.
In Hungarian notation, a variable name starts with a group of lower-case letters
which are mnemonics for the type or purpose of that variable, followed by
whatever name the programmer has chosen
The first character of the given name can be capitalised to separate it from the
type indicators (as in CamelCase). Otherwise the case of this character denotes
scope.
C++

Horizon

24

The Systems Hungarian Notation :


In Systems Hungarian notation, the prefix encodes the actual data type of the
variable. For example:
lAccountNum : variable is a long integer ("l")
arru8NumberList : variable is an array of unsigned 8-bit integers ("arru8")
szName : variable is a zero-terminated string ("sz")
bReadLine(bPort,&arru8NumberList) : function with a byte-value return
code.
The Apps Hungarian Notation :
Apps Hungarian notation does not encode the actual data type, but rather, it
gives a hint as to what the variable's purpose is, or what it represents.
rwPosition : variable represents a row ("rw")
usName : variable represents an unsafe string ("us"), which needs to be
"sanitized" before it is used
strName : Variable represents a string ("str") containing the name, but does
not specify how that string is implemented
It is possible for code using Apps Hungarian notation to sometimes contain
Systems Hungarian when describing variables that are defined solely in terms of
their type.
C++

Horizon

25

The Hungarian notation always uses initial lower-case letters as mnemonics.


It does not prescribe the mnemonics themselves. There are several widely used
conventions, but any set of letters can be used, as long as they are consistent
within a given body of code.
Some of the suggested prefixes are :
pX is a pointer to another type X; this contains very little semantic
information.
d is a prefix meaning difference between two values; for instance, dY might
represent a distance along the Y-axis of a graph, while a variable just called y
might be an absolute position. This is entirely semantic in nature.
sz is a null or zero-terminated string. In C, this contains some semantic
information because it's not clear whether a variable of type char* is a pointer
to a single character, an array of characters or a zero-terminated string.
w marks a variable that is a word. This contains essentially no semantic
information at all.
b marks a byte, which in contrast to w might have semantic information,
because in C the only byte-sized data type is the char, so these are sometimes
used to hold numeric values.
C++

Horizon

26

The Rules :
This list of rules is comprehensive, and thus covers both common and rare
situations.
Variables
All variable names are composed of four elements: scope, prefixes, base type,
and qualifiers.
Not all elements are present in all variable names; the only part that is always
present is the base type.
Base Types
The base type should not be confused with the types supported directly by the
programming language; most base types are application specific (and are
based on structures, classes, enumerated values, etc, that are created for that
application).
Tags should be short (typically two or three letters) and somewhat mnemonic.
Because of the brevity, the mnemonic value will be useful only as a reminder
to someone who knows the application, and has been told what the basic
types are; the name will not be sufficient to inform (by itself) a casual viewer
what is being referred to.
It is essential that all tags used in a given application be clearly documented.
This is extremely useful in helping a new programmer learn the code.
C++

Horizon

27

There are a few standard types that appear in many different applications :
f a flag (boolean, logical)
ch a character.
sz a zero-terminated string. This is the way strings are represented in C/C+
+.
fn a function. Since about the only thing you can do with a function is take
its address, this almost always has a "p" prefix.
There are some more types that appear in many applications :
b a byte (8 bits).
w an int (as defined by the C/C++ compiler -- it does not imply a specific
size).
sw a short word (16 bits).
lw a long word (32 bits).
llw a long long word (64-bits).

C++

Horizon

28

Prefixes
The standard prefixes are:
p a pointer. For example, a pch is a pointer to a character.
a an array. For example, an ach is an array of characters.
I an index into an array. For example, an ich is used to index an ach (with
a ch as the result, i.e. ch = ach[ich]).
c a count.
d a difference between two instances of a type.
gr a group, usually of variable-size objects.
e an element of an array.
u a union. This is a rarely used prefix; it is used for variables that can hold
one of several types.
w a wide value. This is used in conjunction with ch and sz for double-byte
characters
u an unsigned value. Typically used as a prefix to w, lw, and sw.

C++

Horizon

29

Qualifiers
The standard qualifiers are:
Min the first element in a set. This is very similar to First, but typically refers
to the actual first element of an array, not just the first to be dealt with.
Max the upper limit of elements in a set.
Most the current last element in a set.
First the first element (in a set) to be dealt with.
Last the last element (in a set) to be dealt with.
Scope
Most variables are used within the scope of a function. For those that have a
broader scope, one of the following scopes is placed at the beginning of the
variable name (before any prefixes) :
m_ a member of a class. This is used to label the variables (but not methods)
in a class. This is used so that member variables can be easily
distinguished from local variables in the class methods.
g_
a global. This is applied to variables that are available to numerous
functions in multiple files.
s_
a static. This is applied to variables that are available to multiple
functions all within the same file, but not available to functions in other
files (essentially a global variable, but private to one file).
C++

Horizon

30

Functions
The above rules used for variable names do not work as well for functions.
Whereas the type of a variable is always quite important, specifying how that
variable may be used, the important part of a function is typically what it does.
In addition, the context for functions is usually the entire program, so there is more
chance for conflict.
Some rules for functions are as follows :
All function names are distinguished from variable names by the use of some
standard punctuation; in C/C++ this is done by capitalizing the first letter of the
function name (all variable names begin with a lowercase type).
If the function returns a value, its name begins with the type of the value
returned; if no value is returned, the name must not begin with a valid type.
If the function does more than just determine a return value based on its
parameters, follow the return type (if any) with a few words describing what the
function does (a verb followed by an object is usually good). Each word should
be capitalized.
If the function is defined as static (it can be called only from functions within its
file), an underscore (_) should be placed at the beginning of the name.
C++

Horizon

31

C++

C++

Horizon

32

A Sample C++ Program


#include <iostream>
using namespace std ;
int main( )
{
cout << Good Morning<< endl ;
cout << Please enter a number\n ;
int i ;
cin>>i ;
cout << The number you have entered is << i << endl ;
}

C++

Horizon

33

Structure of C++ Program


The code is organized as follows :
The class declarations are placed in a header file.
The definitions of member functions go in another file.
The main program is placed in the third file which includes the
other two files as it will be using the classes created in those
files.

C++

Horizon

34

Generating the Executable


The following command compiles and links a program to
generate an executable :
c++ try.c
This command generates a file called [Link] which is an
executable file.
The following only compiles the program file to generate an
object file :
c++ -c try.c
This generates a file try.o which is the object file
corresponding to the program file try.c.
This object file can then be linked by the c++ command to get
the executable file [Link].
C++

Horizon

35

The default executable produced by c++ is [Link] as the


executable. But the executable name can be changed by using
the o flag with c++
c++ try.o -o [Link]
c++ try.c -o [Link]
This command produces [Link] as the executable file.

C++

Horizon

36

Data Types and Control


Structures
Data Types :
The data types are the same as in C.
There is a new kind of variable that is introduced in C++. It is the
reference variable.
Example :
int i = 10 ;
int & x = i ;
x = 20 ;
cout<<value of i is <<i<<endl ;
Output : value of i is 20
C++

Horizon

37

A reference variable :
is another name for an already created variable
must be initialized at the time of declaration
can be created for built in as well as user defined data types
References are compiled as pointers which are implicitly
dereferenced at each use involve hidden dereference
operations that are costly
Application of reference variables in argument passing :
void f(int &i)
{ i += 10 ;}
main( )
{
int k = 12 ;
f(k) ;
cout << k ;
}
C++

Horizon

38

Using the const qualifier :


If a function argument is declared as const then that argument can
not be modified within the function. Else a compiler error is
generated.
Example :
void func( const int &x, int y) {
x = 10 ; // generates an error
y += x ; }

constant pointer (must be initialized during declaration) :

i.e., following statement is illegal :


char * const ptr1 = HELLO ;
ptr1 = new char[10] ;
// the address in ptr1 can not be modified henceforth

pointer to a constant :
int const * ptr2 = &m ;//here int and const can be interchanged without causing any effect
// ptr2 can point to any variable of matching type, but the contents of what it
And following is legal :
points to can not be changed. i.e., following is illegal :
*ptr2 = 80 ;

C++

Horizon

ptr2 = &k ;

39

The following code depicts the difference between a 'constant


pointer' and 'pointer to a constant' :
main() {
int x = 10, y = 9 ;
int *const p1 = &x ;
int const *p2 = &x ;
*p1 = 77 ;
*p2 = 55 ;
p1 = &y ;
p2 = &y ;
}

C++

Horizon

40

A member function in a class can be declared as const as given


below. In this case such a member function can not modify the
object on which the function has been invoked.
Example :
class someclass {
int datamem ;
public :
void memfunc (int y) const {
datamem = y ; // generates an error
}
}

C++

Horizon

41

Control Structures :
These are the same as in C.

C++

Horizon

43

Operators in C++
All C operators are valid in C++. The additional new
operators of C++ are listed below :
<<
insertion operator
>>
extraction operator
::
scope resolution operator
::*
to declare pointer to class member
->*
to access class member using pointer to the object
and pointer to that member
.*
to access class member using object name and
pointer to that member
delete memory release operator
new memory allocation operator

C++

Horizon

44

Examples of ::* and .* and ->* operators


class temp {
public :
char *val ;
void print(int x) { cout<<val<<"::"<<x<<'\n' ; }
temp(char *v)
{val = v ;}
};
typedef void (temp :: *P)(int) ;
void main() {
temp
z1("z1"), z2("z2") ;
temp
*ptr = &z2 ;
P pf = &temp::print ;
[Link](1) ; (z1.*pf)(2) ;
[Link](3) ; (ptr->*pf)(4) ;
(z2.*pf)(5) ;
}

C++

Horizon

46

Associativity of Operators
Unary operators and the assignment operators are right
associative.
Thus
a = b = c means a = (b = c)
AND
* p++ means * ( p++ )
The remaining operators are left associative.
Thus
a + b + c means (a + b) + c
a + b * c means a + (b * c) [* has higher precedence than +]
a + b c means (a + b) - c
C++

Horizon

47

Inline Functions
An inline function is a function for which the function call is
replaced by the complete function code by the compiler.
(Similarity with the macros)
Requirement for inline functions :There is a cost involved in
function calls (jumping to the func, saving registers, pushing
arguments to stack and returning back) that becomes appreciable
for small functions. Inline functions overcome this overhead.
It is different and far more superior than macros in the following
respects :
Inline functions are handled by the compiler while macros are
handled by the pre processor.
Macros do not undergo the usual error checking. This is not
true for inline functions.
C++

Horizon

48

If expressions are passed to macros then they are as is


passed to the replaced code. In case of inline functions
expressions passed as input arguments are first evaluated and
then passed to the invoked function.
Example :
inline int sq(int a)
#define sq(a) a*a
{
return (a*a) ;
main( )
}
{
cout << sq(3+2) ;
main( )
}
{
cout << sq(3+2) ;
}
Output :
25
11
C++

Horizon

49

How to make a function inline ?


By using the inline prefix to the function definition.
The use of the inline keyword does not ensure that the
function would definitely become inline. It is only a request to
the compiler which may ignore the request in case of the
following situations :
the function is too long
for functions returning values if a loop, a switch or a goto
exists
for functions not returning values if a return statement exists
if functions contain static variables
if the function is recursive
But inline functions make the program take up more memory
because the statements of these functions are reproduced at
each point the function is called.
C++

Horizon

50

Class Definition
A class can be seen as an extension of a structure with the
following differences :
A class by default provides the features of data hiding while
a structure does not.
By default the members of a class are private while those of
a structure are public.
A class data type is used to create a specific category
encapsulating the data and the functional properties of the
category.

C++

Horizon

51

A sample declaration :
class item
{
int number ;
float cost ;
public :
void getdata(int a, float b)
{
//code for getdata
}
void dispdata( )
{
//code for dispdata
}
};
C++

Horizon

52

In C++ we can declare variables of structures as follows :


struct my_struct
{
//members of the structure
};
my_struct s1, s2 ;
Thus we do not need to use the keyword struct while
declaring variables of the structure data type.

C++

Horizon

53

Object Creation
What is an object ?
An object is an instance of a class just as a variable is an instance
of a built-in data type or a user-defined structure.
Object Creation :
Objects for an existing class my_class can be declared as follows :
my_class obj1 , obj2 ;
Objects are also created by the use of the keyword new

C++

Horizon

54

What happens when an object is created ?


Objects are created statically in C++ through the above piece of
code.
For every object created, a unique block of memory is allocated
for all the data members of the class.
The member functions are loaded only once for the whole
class.
All the objects of a class share the same set of functions.

C++

Horizon

55

member function#1

COMMON FOR ALL OBJECTS


OF THE SAME CLASS

member function#2

Object #1
member variable#1

memory created when


functions defined

Object #2
Object #3
member variable#1 member variable#1

member variable#2 member variable#2 member variable#2


member variable#3 member variable#3 member variable#3
memory created when
objects defined
C++

A UNIQUE SET PER OBJECT


Horizon

56

Member Access :
For the item class declared earlier :
main( )
{
item i1 , i2 ;
[Link]( 10 , 12.6 ) ;
[Link]( 13 , 7.8 ) ;
[Link]( ) ;
[Link]( ) ;
}
The members of the class are accessed by using the dot operator
on the class object just as in the case of a structure.

C++

Horizon

57

Private members :
The members declared in the private section of a class have the
following properties :
Their accessibility is limited within the class only.
They are hidden for the outside world.
Public members :
The members declared in the public section of a class have the
following properties :
They can be accessed from any part of the code.
Every class must contain at least one non private member.

C++

Horizon

58

Example :
For the item class declared earlier :
main( )
{
item

i1 ;

[Link]=10; //error:cant access private member outside class.


[Link](10,12.6); // public mems can be accessed outside class
[Link]( ) ;
}

C++

Horizon

59

Scope Resolution Operator


It can be used to access a global variable from within an inner
block even if the inner block tries to hide the global variable
Example :
OUTPUT :
int
m = 10 ;
in inner loop
main( )
m=30
{
::m=10
int m = 20 ;
in outer loop
{
m=20
int m = 30 ;
::m=10
cout<<in inner loop\nm=<<m<<\n ;
cout<<::m=<<::m<<\n ;
}
cout<<in outer loop\nm=<<m<<\n ;
cout<<::m=<<::m<<\n ;
}
C++

Horizon

60

It is used for providing outside the class definition for member


functions.
Example :
class item {
int x , y ;
public :
void getdata(int a , int b) ;
void dispdata( ) ;
};
void item :: getdata(int a , int b) {
// code for getdata
}
void item :: dispdata( ) {
// code for dispdata
}
C++

Horizon

61

Default Arguments
This mechanism allows invocation of a function without specifying
all the arguments.
This is possible if the function has been declared with default
arguments.
Example :
float amount ( float p, int time, float r = 0.15) ;
Such a function can be invoked in either of the following ways :
float val = amount(5000, 7) ;
float val = amount(3000, 3, 0.18) ;
In the first case the third argument takes the default value of 0.15
C++

Horizon

62

Only trailing arguments can be assigned default values.


A function can have any number of default values.
They provide the flexibility to have scope for addition of new
parameters to an existing function.

C++

Horizon

63

Method Overloading
It allows us to use the same name for different functions.
It is generally used for functions with similar functionalities.
It results in static polymorphism also known as early
binding.
The functions with the same name are identified on the basis of
their unique input argument list.
Example :
Let there exist the following function declarations :
int add(int a , int b , int c) ;
int add(int a , int b) ;
Let there be the following function calls :
add(3 , 8) ; // invokes the second version
add(1 , 2 , 3) ; // invokes the first version
C++

Horizon

64

The function selection involves the following steps :


The compiler first tries to find an exact match in which the
types of actual arguments are the same and use that function.
If an exact match is not found, the compiler uses the integral
promotions to the actual arguments, example :
char to int
float to double
When both the above fail, the compiler tries to use the built in
conversions to the actual arguments and then uses the function
whose match is unique. Example :
int to double
derived* to base*
Finally if nothing works, the compiler matches using userdefined conversions.
C++

Horizon

65

If the conversion is possible to have multiple matches, then the


compiler generates an error message.
Example : Declarations Function call
long sq(long n) sq(10) ;
double sq(double x)
This generates an error because int can be converted to both
long as well as double.
Declarations Function call
void f(int x, int y, int z = 80) f(2, 20)
void f(int x, int y) f(3, 33, 333)
The first call generates an error while the second call executes
the first function.

C++

Horizon

66

Overloading Member Functions


from base and derived classes

A member function named 'f' in a class A will hide all other members named 'f'
in the base classes of A, regardless of return types or arguments.
To overload, rather than hide, a function of a base class A in a derived class B,
you introduce the name of the function into the scope of B with a using
declaration.
This is shown in the following code :

class par {
public :
void f() {cout<<"def f in par\n" ;}
void f(int i) {cout<<"1 arg f in par\n" ;}
void g() {cout<<"def g in par\n" ;}
};
class ch : public par {
public :
using par::f ;
void f(int i, int j) {cout<<"2 arg f in ch\n" ;}
};
main() {
ch obj ;
obj.g() ;
obj.f() ; obj.f(9) ; obj.f(2, 3) ;
}
C++

Horizon

67

Constructors and Destructors


Constructors :
are special functions
have the same name as the class name
are invoked automatically every time an object of an
associated class is created.
can not be invoked explicitly
do not have a return type
should not be declared in the private section of a class, else
objects of that class can not be created
[there should be at least one public constructor]
C++

Horizon

68

can be overloaded
can have default arguments
can not be referenced by their addresses
a constructor that takes no parameters is called the default
constructor
if there is no constructor within the class then and only then the
compiler supplies with a default constructor

C++

Horizon

69

Copy Constructor :
It takes a reference of an object of the same class as itself as an
argument.
It creates a new object by initializing each member of the new object
with the value of the corresponding member of the object passed as
argument.
When no copy constructor is defined within the class, the compiler
supplies its own copy constructor.
Example :
class temp {
public : temp( ) { cout << "constr\n" ; }
temp (temp &var) { cout << "copy constr\n" ; }} ;
main( ) {
temp
t1 , t4 ;
temp
t2(t1) ; // copy constructor invoked
temp
t3 = t1 ; // copy constructor invoked
t4 = t1 ; } // copy constructor not invoked
C++

Horizon

70

The following code displays how a pass-by-value invokes the copy constructor :
class temp {
public :
temp() {cout << "constr\n" ;}
temp(temp &) {cout << "copy constr\n" ;}
~temp() {cout << "destr\n" ;} } ;
void f(temp t) { }
void g(temp &t) { }
main( ) {
temp
obj ;
cout<<invoking f ----\n ;
f(obj) ;
cout<<invoking g ----\n ;
g(obj) ;
}

C++

Horizon

71

Destructors :
are special functions like constructors
have the same name as the class name preceded by a tilde
can be invoked explicitly
are invoked implicitly by the compiler upon exit from the
program (or block or function); basically it is invoked when
the object is no longer accessible
can not return anything and has no return type
can not take any input arguments overloaded destructors are
not possible
should not be declared in the private section of a class
C++

Horizon

72

Destructors are not inherited.


The body of a destructor is executed before the member
objects.
Destructors for nonstatic member objects are executed before
the destructors for base classes.
Member functions may be called from within a destructor.
An object of a class with a constructor / destructor cannot be a
member of a union.
Destructors are invoked implicitly:
when an auto or temporary object goes out of scope
for constructed static objects at program termination
through use of delete for objects created by new.
C++

Horizon

73

Can be explicitly called as shown in the following code:


class X {
int x ; char ch ;
public :
X(){cout<<"constr\n" ;}
~X(){cout<<"destr\n" ;}
};
main() {
X obj ;
X *ptr = new X ;
cout<<"explicit destr invocation\n" ;
ptr->~X() ; //delete ptr ; instead of ptr->~X() will cause further error
memcpy(ptr, &obj, sizeof(X)) ;
delete ptr ;
}
C++

Horizon

74

New and Delete Operators


These are used for dynamic allocation (new) and de-allocation
(delete) of variables and objects.
An object created by new is destroyed only when it is deleted.
Example :
main( )
{
class temp {
temp *ptr ;
CONS
public :
ptr = new temp ;
temp( ) {
}
cout << CONS\n ;
main( )
}
{
CONS
temp *ptr ;
~temp( ) {
DESTR
ptr = new temp ;
cout<<DESTR\n ;
delete(ptr) ;
}
}
};
C++

Horizon

75

Other Examples :
The following creates an integer variable with initial value 12 ;
int
* p1 = new int (12) ;
The following creates a memory space for an array of 10 integers :
int
*p2 = new int [10] ;
Code :
class temp {
public :
temp( ) {
cout<<CONS\n ; }
~ temp( ) {
cout<<DESTR\n; }
};
main( ) {
temp *p1 = new temp[5] ;
delete[ ] p1 ; }
C++

Horizon

Output :
CONS
CONS
CONS
CONS
CONS
DESTR
DESTR
DESTR
DESTR
DESTR

76

Following are the advantages of new over malloc :


It automatically computes the size of the data object, the use of
the sizeof operator is not required.
It automatically returns the correct pointer type, no type casting
is required.
It is possible to initialize the object while creating the memory
space.
As the other operators, new and delete can also be overloaded.
NEW RETURNS NULL POINTER IN CASE OF FAILURE.

C++

Horizon

77

Stack and Heap


The memory that a program uses is typically divided into four different areas :
The code area, where the program sits in the memory
The data segment, where the global variables are stored
The heap, from where the dynamically allocated variables are allocated
The stack, from where the parameters and the local variables are allocated
The Heap
The heap (also known as the free store) is a large pool of memory used for
dynamic allocation.
In C++, when the new operator is used to allocate memory, this memory is
assigned from the heap.
Because the precise location of the memory allocated is not known in advance,
the memory allocated has to be accessed indirectly which is why new
returns a pointer.
Sequential memory requests may not result in sequential memory addresses
being allocated.
When a dynamically allocated variable is deleted, the memory is returned to
the heap and can then be reassigned as future allocation requests are received.
C++

Horizon

78

The heap has advantages and disadvantages:


1) Allocated memory stays allocated until it is specifically deallocated (beware
memory leaks).
2) Dynamically allocated memory must be accessed through a pointer.
3) Because the heap is a big pool of memory, large arrays, structures, or classes
should be allocated here.
The Stack
A stack is a container that holds other variables (much like an array).
However, whereas an array allows access and modification of elements in
any order, a stack is more limited.
The operations that can be performed on a stack are identical to the ones
above:
1) Look at the top item on the stack (usually done via a function called
top())
2) Take the top item off of the stack (done via a function called pop())
3) Put a new item on top of the stack (done via a function called push())
A stack is a last-in, first-out (LIFO) structure - the last item pushed onto the
stack will be the first item popped off.
C++

Horizon

79

The stack in action


The sequence of steps that takes place when a function is called is as follows :
The address of the instruction beyond the function call is pushed onto the
stack. This is how the CPU remembers where to go after the function returns.
Room is made on the stack for the functions return type. This is just a
placeholder for now.
The CPU jumps to the functions code.
The current top of the stack is held in a special pointer called the stack frame.
Everything added to the stack after this point is considered local to the
function.
All function arguments are placed on the stack.
The instructions inside of the function begin executing.
Local variables are pushed onto the stack as they are defined.
C++

Horizon

80

When the function terminates, the following steps happen:


The functions return value is copied into the placeholder that was put on the
stack for this purpose.
Everything after the stack frame pointer is popped off. This destroys all local
variables and arguments.
The return value is popped off the stack and is assigned as the value of the
function. If the value of the function isnt assigned to anything, no assignment
takes place, and the value is lost.
The address of the next instruction to execute is popped off the stack, and the
CPU resumes execution at that instruction.
Stack overflow
Stack has a limited size, and can only hold a limited amount of information.
If the program tries to put too much information on the stack, stack overflow will
result.
Stack overflow happens when all the memory in the stack has been allocated
in that case, further allocations begin overflowing into other sections of memory.
C++

Horizon

81

Stack overflow is generally the result of allocating too many variables on the
stack, and/or making too many nested function calls (where function A calls
function B calls function C calls function D etc)
Overflowing the stack generally causes the program to crash.
The stack has advantages and disadvantages:
Memory allocated on the stack stays in scope as long as it is on the stack. It is
destroyed when it is popped off the stack.
Because the stack is relatively small, it is generally not a good idea to do
anything that eats up lots of stack space. This includes allocating large arrays,
structures, and classes, as well as heavy recursion.

C++

Horizon

82

Usage of typedef
A typedef declaration introduces a name that, within its scope, becomes a
synonym for the type given by the type-declaration portion of the declaration.
This is done as follows :
typedef type-declaration synonym;
A typedef declaration can be used to construct shorter or more meaningful
name for a type already defined by the language or for a user-defined type.
In contrast to the class, struct, union, and enum declarations, typedef
declarations do not introduce new types - they introduce new names for
existing types.
The typedef specifier can not be used inside a function definition.
Typedef names share the name space with ordinary identifiers. Therefore, a
program can have a typedef name and a local-scope identifier by the same
name.

Any type can be declared with typedef, including pointer, function, and array
types.
A typedef name can be declared for a pointer to a structure or union type before
the structure or union type is defined, as long as the definition has the same
visibility as the declaration.
Examples
One use of typedef declarations is to make declarations more uniform and
compact. For example:
typedef char CHAR;
// Character type.
typedef CHAR * PSTR;
// Pointer to a string (char *).
PSTR strchr( PSTR source, CHAR target );
typedef unsigned long ulong;
ulong ul; // Equivalent to "unsigned long ul;"
To use typedef to specify fundamental and derived types in the same
declaration, declarators can be separated with commas. For example:
typedef char CHAR, *PSTR;

The following example provides the type DRAWF for a function returning no
value and taking two int arguments:
void DRAWF( int, int );
After the above typedef statement, the declaration
DRAWF box;
would be equivalent to the declaration
void box( int, int );
typedef is often combined with struct to declare and name user-defined types:
typedef struct mystructtag {
int i; double f;
} mystruct;
int main() {
mystruct ms;
ms.i = 10; ms.f = 0.99;
printf("%d %f\n", ms.i, ms.f);
}

Recursion
Recursion is when a function calls itself.
Thus in the course of the function definition there is a call to that very same
function.
A check is made to see if a certain condition is true and in that case an exit
(return from) from the recursive function is made.
The case in which the recursion ends is called a base case.
Additionally, just as in a loop, some value must change and we must
incremently advance closer to our base case.
Example :
void myFunction( int counter) {
if(counter == 0)
return;
else
{
cout <<counter<<endl;
myFunction(--counter);
return;
}
}
C++

Horizon

86

Every recursion should have the following characteristics :


A simple base case which we have a solution for and a return value.
Sometimes there are more than one base cases.
A way of getting our problem closer to the base case. I.e. a way to chop out
part of the problem to get a somewhat simpler problem.
A recursive call which passes the simpler problem back into the function.
The key to thinking recursively is to see the solution to the problem as a
smaller version of the same problem.

C++

Horizon

87

Command Line Arguments


arguments received by the program that are given at the
command line while starting a program
in the following definition of main function :
main( int argc, char ** argv)
the command line arguments are received inside argc and argv
as follows :
argc : holds the number of parameters including the program
name
argv : is an array of strings
each string holds one argument
the first string pointed by argv[0] is the program name
the remaining strings held in argv[1] to argv[argc 1]
are the input arguments to the program
C Data Structures

Horizon

88

Static Members

STATIC DATA MEMBERS :


Static member variables have the following properties :
It is initialized to 0 by default when it is created.
Only one copy of a static data member is created per class.
A static data member is shared by all the objects of the that
class.
A static member variable must be defined outside the class.
Example :
THIS DECLARATION CREATES
class temp {
THE STATIC VARIABLE
static int x ;
};
int temp :: x ;
C++

Horizon

89

It can be accessed with the class name also.


Example :
temp::x = 19 ;
Static variables are also known as class variables and are used
to hold class wide information.
They can be created with some initial value as shown below :
class temp {
static int x ;
};
int temp :: x = 17 ;

C++

Horizon

90

STATIC MEMBER FUNCTIONS :


Static member functions have the following properties :
A static member function can access only the static members
of the class.
A static member function does not have a this pointer. So it
can access nonstatic members of its class only by using . or
-> operators.
A static member function can not be virtual.
There can not be a static and a nonstatic member function with
the same name and the same arguments.

C++

Horizon

91

They can be invoked by using the class name. They can also
be invoked on an object of the class but still there behavior
remains the same.
Example :
class temp {
public :
static void f( ) {
cout<<in static func ;
}
};
main( ){
temp :: f( ) ;
(new temp)->f( ) ;
temp obj ; obj.f( ) ;
}
C++

Horizon

92

For a local variable declared static in a member function :


a static variable is available to the whole program
thus, all instances of the type share the same copy of the
static variable.
Note : Assigning to a static local variable is not thread safe and
is not recommended as a programming practice.
Example :
class C {
public : void Test(int value) {
static int var = 0;
if (var == value)
cout << "var == value" << endl;
else
cout << "var != value" << endl;
var = value; }};
int main() {
C c1; C c2;
[Link](100); [Link](100); }
C++

Horizon

93

Exercises
Create a class stack such that the stack is either for characters
or for integers, the stack type being an input. Maximum
number of items that the stack can hold should be defined by
the user at the time of object creation. Test it by creating two
objects one for integers and one for characters.
Create a class complex which provides the following
functions : add, subtract and multiply. Write only one add
function through which you can add 2 or 3 or 4 complex
numbers. These functions should return the complex number
holding the result.

C++

Horizon

94

Create a class hospital with the following data members :


name, staffStrength, noOfPatients, areaCode. Let there be
the following member functions of the class :
patientAdmitted, patientReleased, staffResigns, staffJoins,
displayInfo. Let there be a function which shows the total
number of hospitals on the basis of the area code, assume
that the area is divided into 3 area codes. Test the class by
creating sufficient number of objects.

C++

Horizon

95

Friend Functions and Classes


Friend functions are those functions which have access to
the private and protected members of a class although they
are themselves not members of the class.
Example :
class temp {
int
i;
public :
temp( ) {i = 10 ;}
friend void disp( temp t) ;
};
void disp( temp t) {
cout <<t.i ;
}
C++

Horizon

96

Following are the special features of a friend function :


It is not in the scope of the class to which it has been declared
as a friend.
It cannot access member names directly and can access the
members only through an object of the class. That means the
friend function accesses the members of a class for an object of
that class.
It can be declared as a friend either in the public or private
section of the class, its meaning remaining the same.
Friendship is not a symmetric relationship. It is neither
inherited nor transitive.
When a friend declaration refers to an overloaded name or
operator, only the function specified by the argument types
becomes the friend.
C++

Horizon

97

Some Examples :
Following code shows how an outside function is friendly to a class :
class temp {
int
i;
public :
temp( ) {i = 10 ;}
friend void disp( temp t) ;
};
void disp( temp t) {
cout <<t.i ;
}
main( ) {
temp t ;
disp(t) ;
}
C++

Horizon

98

Following code shows how a function of one class be friendly to a


function of another class :
class X {
public :
int f( ) { /* code */ }
};
class Y {
friend int X::f( ) ;
};
If a class (X) declares another class (Y) as a friend class then all
the members of the friend class (Y) can access all the members of
the class X.
Following code shows how a class can be declared as friendly :
class X {
friend class Y ;
};
C++

Horizon

99

Following code shows friendship is neither transitive nor inherited:


class A {
int a ;
friend class B ;
};
class B {
friend class C ;
};
class C {
// NON TRANSITIVE
public : void f(A *p) {
p -> a++ ; }
//error
};
class D : public B {
// NON INHERITABLE
public : void f(A *p) {
p -> a++ ; }
//error
};
C++

Horizon

100

Following code shows friend declaration referring to an


overloaded name :
class test {
int i ;
friend void f(test k) ;
friend void f(test k, char c) ;
public :
test(){i = 10 ;}
};
void f(test i, char c) {cout << "in 1st f :: "<<i.i<<"\n" ;}
void f(test i) {cout << "in 2nd f :: "<<i.i<<"\n" ;}
void main() {
testobj ;
f(obj) ;
}
C++

Horizon

101

Declaring a class to be a friend also implies that private and


protected names from the class granting friendship can be used in
the class receiving it. Example :
class X {
struct sx {} ;
void f() {cout<<"in class X\n" ;}
friend class Y ; } ;
class Y {
public :
void f_Y() {
X::sx sx_obj ;
X x_obj ;
x_obj.f() ;} } ;
void main() {
Y y_obj ;
y_obj.f_Y() ;
}
C++

Horizon

102

Operator Overloading
This feature provides with the flexibility of creating new definition
for most of the C++ operators.
Following operators can not be overloaded :
class member access operators ( . and .* )
scope resolution operator ( :: )
size operator ( sizeof )
conditional operator ( ?: )

C++

Horizon

103

Only the semantics of an operator can be modified, not its syntax.


That is, the rules like the number of operands and precedence
rules can not be modified.
Operator overloading is achieved through the use of operator
functions.
Operator functions are either :
non-static member functions or
friend functions

C++

Horizon

104

OVERLOADING UNARY OPERATORS :


Using Member Functions :
class vector {
int x1, x2, x3 ;
public :
vector( ) { x1 = 10 ; x2 = 20 ; x3 = 30 ; }
void operator ( ) {
x1 = -x2 ; x2 = -x3 ; x3 = -x1 ;
}
void disp( ) {
cout << x1 ::<<x1<< x2::<<x2<< x3::<<x3 ;
}
};
main( ) {
vector v1 ;
-v1 ;
[Link]( ) ;
} C++
Horizon
105

Using Friend Function :


class vector {
int x1, x2, x3 ;
public :
vector( ) { x1 = 10 ; x2 = 20 ; x3 = 30 ; }
friend void operator (vector &v ) ;
void disp( ) {
cout << x1 ::<<x1<< x2::<<x2<< x3::<<x3 ;
}
};
void operator (vector &v) {
v.x1 = -v.x2 ; v.x2 = -v.x3 ; v.x3 = -v.x1 ;
}
main( ) {
vector v1 ;
-v1 ;
[Link]( ) ;
}
C++

Horizon

106

OVERLOADING BINARY OPERATORS :


Using Member Functions :
left hand operand :class vector {
invokes the operator func
int x1, x2, x3 ;
right hand operand :public :
passed as an argument
vector( int a, int b, int c) { x1 = a ; x2 = b ; x3 = c ; }
vector operator +( vector v) {
return vector (2*x1 + v.x1, 2*x2 + v.x2, 2*x3 + v.x3) ;
}
void disp( ) {
cout << x1 ::<<x1<< x2::<<x2<< x3::<<x3 ;
}
};
main( ) {
vector v1(10, 20, 30) , v(1, 2, 3) ;
vector v2 = v1+v ;
[Link]( ) ;
}
C++
Horizon
107

Using Friend Function :


class vector {
int x1, x2, x3 ;
public :
vector( int a, int b, int c) { x1 = a ; x2 = b ; x3 = c ; }
friend vector operator +( vector v, vector u) ;
void disp( ) {
cout << x1 ::<<x1<< x2::<<x2<< x3::<<x3 ;
}
};
vector operator +( vector v, vector u) {
return vector (u.x1-v.x1, u.x2-v.x2, u.x3-v.x3) ;
}
main( ) {
vector v1(10, 20, 30) , v(1, 2, 3) ;
vector v2 = v1+v ;
[Link]( ) ;
}
C++

Horizon

108

Rules for overloading operators :


Only existing operators can be overloaded.
The overloaded operator must have at least one user defined
type operand.
The syntax rules of the original operators can not be changed.
When using binary operators overloaded through a member
function, the left hand operand must be an object of the
relevant class.
Binary arithmetic operators like +, -, *, / must explicitly
return a value.

C++

Horizon

109

OPERATORS THAT CANNOT BE OVERLOADED USING


FRIENDS

=
()
[]
->

Assignment operator
Function call operator
Subscripting operator
Class member access operator

This is to ensure that their first operands are lvalues.


{Friend functions can take variables, i.e., non-objects as first
argument also. This should not happen for these overloaded
operators.}
[
An lvalue is an expression referring to an object or function.
Originally the term was used to mean something that can be on
the left hand side of an assignment
]
C++

Horizon

110

WHY THE NEED FOR THE FRIEND FUNCTIONS FOR


OPERATOR OVERLOADING
Situations arise where a member function usage for operator
overloading does not work.
Eg :
A = 2 + B // both A and B are objects.
This can not be achieved through a member function because
the left hand operand is responsible for invoking the member
function.
In this case the left hand operand is not an object.

C++

Horizon

111

<< and >> operators :


These can be overloaded using only friend functions.
- The left hand operands for these operators are cout and
cin.
- These operands are system defined objects of the system
defined classes istream and ostream.
- So a user can only create a friend function to overload
these operators.

C++

Horizon

112

class complex { private : int real, img ;


public : complex() {}
complex(int r, int i) {
real = r; img = i ; }
friend ostream & operator << (ostream & s, complex & c) ;
friend istream & operator >> (istream & s, complex & c) ; } ;
ostream & operator << (ostream & s, complex & c) {
s<<"("<<[Link]<<","<<[Link]<<")"<<endl ;
return s ; }
istream & operator >> (istream & s, complex & c) {
s>>[Link]>>[Link] ;
return s ; }
void main( ) {
complex c1, c2(1, 2) ;
cout<<endl<<"c2 = "<<c2 ;
cout<<"enter a complex number\n" ;
cin>>c1 ;
cout << "c1 = "<<c1 ;
}
C++

Horizon

113

The operator<< function returns a reference to the ostream it was


called for, so that another operator<< can be applied to it.
Example :
cout<<x = <<x ;
This statement is interpreted as :
([Link]<<(x = )).operator<<(x)
Thus when several items are printed by a single output statement,
they will be printed from left to right.

C++

Horizon

114

OVERLOADING THE SUBSCRIPT OPERATOR


Subscripting is considered a binary operator.
The expression x [ y ] is interpreted as [Link][ ] (y) where
x is a class object.
class vector {
int arr[10] ;
public : vector( )

{
for (int i = 0; i < 10; i++)
arr[i] = i+1 ; }
friend int operator +(vector v, int x) ;
int operator [ ](int x){ int temp = 1 ;
for (int i = 0; i < x; i++)
temp = temp * arr[i] ;
return temp ;}} ;
int operator +(vector v, int x){
int temp = 1 ;
for (int i = 0; i < x; i++)
temp = temp * [Link][i] ;
return temp ;}
main( ) {
vector v1 ;
cout << "\nsubscript result is : " << v1[4] ;
cout << "\naddition result is : " << v1+3 ;}
C++

Horizon

115

THE CLASS MEMBER ACCESS


Class member access using -> is considered a unary operator.
The expression x -> y is interpreted as ([Link]->())->y
where x is a class object.

C++

Horizon

116

THE INCREMENT AND DECREMENT OPERATORS


The ++ and the -- operators can be overloaded as follows :
In the prefix form :
through a friend function:
- takes one argument0
through member function
- takes no argument
In the postfix form :
through a friend function:
- takes two arguments the second argument automatically
passed as 0
through member function
- takes one argument
C++

Horizon

117

overloaded ++, -- using member functions


class vector {
int x1, x2, x3 ;
public :
vector( ) { x1 = 10 ; x2 = 20 ; x3 = 30 ; }
//postfix form
void operator ++(int i) {
for(int cntr = 0; cntr < 2; cntr++) {
x1++ ; x2++ ; x3++ ; } }
//prefix form
void operator ++( ) { x1++ ; x2++ ; x3++ ; }
void disp( ) {
cout << "\n\nx1 ::"<<x1<<" x2::"<<x2<<" x3::"<<x3 ;}
};
main( ) {
vector v1 ; [Link]() ;
v1++ ; [Link]() ;
++v1 ; [Link]() ;
}
C++

Horizon

118

overloaded ++, -- using friend functions


class vector {
int x1, x2, x3 ;
public :
vector( ) { x1 = 10 ; x2 = 20 ; x3 = 30 ; }
friend void operator ++(vector &v, int j) ;
friend void operator ++(vector &v) ;
void disp( ) { cout << "\n\nx1 ::"<<x1<<" x2::"<<x2<<" x3::"<<x3 ;
};
void operator ++(vector &v, int j) {
for(int cntr = 0; cntr < 2; cntr++) { v.x1++ ; v.x2++ ; v.x3++ ; }
}
void operator ++(vector &v) {
v.x1++ ; v.x2++ ; v.x3++ ; }

main( ) {
vector v1 ; [Link]() ;
v1++ ; [Link]() ;
++v1 ; [Link]() ;
}
C++

Horizon

119

operator ( )

class A {
public :
void operator () () {
cout<<"func called\n" ;
}

void operator() (int x, char c) {


cout<<"another f : "<<x<<" "<<c<<endl ;
}
void f() {cout<<"in f\n" ;}
};

void main() {
A obj ;
obj() ;
obj(10, 'k') ;
}
C++

Horizon

120

Exercises

Create a class RationalNumber (fractions) with the following capabilities:


_ Create a constructor that prevents a 0 denominator in a fraction, reduces or
simplifies fractions that are not in reduced form and avoids negative
denominators.
_ Overload the addition, subtraction, multiplication and division operators for
this class.
_ Overload the relational and equality operators for this class.

Develop a class Polynomial. The internal representation of a Polynomial is an


array of terms. Each term contains a coefficient and an exponent. For example,
the term 2x4 has the coefficient 2 and the exponent 4. Develop a complete class
containing proper constructor and destructor functions as well as set and get
functions. The class should also provide the following overloaded operator
capabilities:
_ Overload the addition operator (+) to add two Polynomials.
_ Overload the subtraction operator (-) to subtract two Polynomials.
_ Overload the assignment operator to assign one Polynomial to another.
_ Overload the multiplication operator (*) to multiply two Polynomials.
_ Overload the addition assignment operator (+=), subtraction assignment
operator (-=), and multiplication assignment operator (*=).
C++

Horizon

121

Shallow vs Deep copying


A shallow copy of an object copies all of the member field values.
This works well if the fields are values, but may not be what is wanted for
fields that point to dynamically allocated memory
the pointer will be copied. but the memory it points to will not be
copied
the field in both the original object and the copy will then point to the
same dynamically allocated memory, which is not usually what is
wanted.
The default copy constructor and assignment operator make shallow copies.
A deep copy copies all fields, and makes copies of dynamically allocated
memory pointed to by the fields.
To make a deep copy, a copy constructor must be written and the assignment
operator overloaded, otherwise the copy will point to the original, with
disastrous consequences.
C++

Horizon

122

Thus :
If an object has pointers to dynamically allocated memory,
and
the dynamically allocated memory must be copied when the original object is
copied,
then a deep copy is required.
A class that requires deep copies generally needs :

A constructor to either make an initial allocation or set the pointer to NULL.


A destructor to delete the dynamically allocated memory.
A copy constructor to make a copy of the dynamically allocated memory.
An overloaded assignment operator to make a copy of the dynamically
allocated memory.

C++

Horizon

123

Type Conversions
Following three types of conversions will be discussed :
from built in type to class type
from class type to built in type
from one class type to another class type

C++

Horizon

124

Built In Type to Class Type :


The following statements are true under this situation :
It is achieved through a constructor function.
This constructor belongs to the destination class.
Example :
class integer {
int
val ;
public :
integer (int i) { val = i ;}
integer(char *s) {val = strlen(s) ;}
};
main( ) {
integer object(10) ;
integer obj = 90 ;
obj = 88 ;
obj = abcd ;
}
C++

Horizon

125

Class Type to Built In Type :


The following statements are true under this situation :
It is achieved through a casting operator function.
This casting operator function belongs to the source class.
User-defined conversion cannot specify a return type
Example :
class vector {
double x, y, z ;
public :
vector() {
x=y=z=9;}
operator double() {
return (x+y+z) ; }
};
main( ) {
vector v ;
double l = v ; }
C++

// NOTE :: no return type specified.

Horizon

126

Class Type to Another Class Type :


The following statements are true under this situation :
It can be achieved through :
a casting operator function, in this case the function
belongs to the source class
a constructor function, in this case the constructor
belongs to the destination class

C++

Horizon

127

Example : c1 is source class and c2 is the destination class.


The following code shows the usage of the casting operator function in
the source class.
class c2 ;
class c1 {
public :
int i, j, k ;
c1(int a, int b, int c) {
i = a; j = b ;k = c ; }
operator c2( ) {
c2 temp ;
temp.x = i+j ; temp.y = k ; return temp ; }
};

The following code shows the usage of the constructor function in the
destination class.
class c2 {
public :
int x, y ;
c2(c1 p) {
x = p.i ; y = p.k ; }
};
C++

Horizon

128

class c2 ;
class c1 {
public :
int i, j, k ;
c1(int a, int b, int c) {
i = a; j = b ;k = c ; }
operator c2( ) ;
};

casting operator func in the


source class
with forward declaration

class c2 {
public :
int x, y ;
c2() {x = 0; y = 0 ;}
};
c1 :: operator c2() {
c2 temp ;
temp.x = i+j ; temp.y = k ; return temp ; }
void main() {
c1 ob1(1, 2, 3) ;
c2 ob2(ob1) ;
}
C++

Horizon

129

class c1 ;
class c2 {
public :
int x, y ;
c2(c1 p) ;
};

constructor func in the


destination class
with forward declaration

class c1 {
public :
int i, j, k ;
c1(int a, int b, int c) {
i = a; j = b ;k = c ; }
};
c2 :: c2 (c1 p) {
x = p.i ; y = p.k ; }
void main() {
c1 ob1(1, 2, 3) ;
c2 ob2(ob1) ;
}
C++

Horizon

130

The std::string class


String objects are a special type of container, specifically designed to operate
with sequences of characters.
Unlike traditional c-strings, which are mere sequences of characters in a
memory array, C++ string objects belong to a class with many built-in features
to operate with strings in a more intuitive way and with some additional useful
features common to C++ containers.
The string class is an instantiation of the basic_string class template, defined in
<string> as:
typedef basic_string<char> string;
The following example shows a simple usage of the class :
#include <iostream.h>
#include <string>
using namespace std ;
void main() {
string
obj("hello") ;
cout<<[Link]()+2 ; }
C++

Horizon

131

In the C++ programming language, the std::string class is a standard


representation for a string of text.
This class removes many of the problems introduced by C-style strings by
putting the onus of memory ownership on the string class rather than on the
programmer.
The class provides some typical string operations like comparison,
concatenation, find and replace, and a function for obtaining substrings.
It can be constructed from a C-style string, and a C-style string can also be
obtained from it.
The main constructors provided by the class are :
string ( );
string ( const string& str );
string ( const string& str, size_t pos, size_t n = npos );
string ( const char * s, size_t n );
string ( const char * s );
string ( size_t n, char c );
template<class InputIterator> string (InputIterator begin, InputIterator end);
C++

Horizon

132

Some important member functions :


length
capacity
find
insert
append
c_str
data
compare
substr
The overloaded operators are :
operator+=
operator=
operator[]

C++

Horizon

133

#include <iostream.h>
#include <string>
using namespace std ;
int main () {
char * cstr, *p;
string str ("Please split this phrase into tokens");
cstr = new char [[Link]()+1];
strcpy (cstr, str.c_str()); // cstr now contains a c-string copy of str
p=strtok (cstr," ");
while (p!=NULL) {
cout << p << endl;
p=strtok(cstr," ");
}
delete[] cstr;
return 0;
}
C++

Horizon

134

#include <iostream>
#include <string>
using namespace std;
int main () {
string str("to be question"); string str2("the "); string str3("or not to be") ;
string::iterator it;
[Link](6,str2); cout << str << endl;

// to be (the )question

[Link](6,str3,3,4); cout << str << endl;

// to be (not )the question

[Link](10,"that is cool",8); cout << str << endl; // to be not (that is )the question
[Link](10,"to be "); cout << str << endl; // to be not (to be )that is the question
[Link](15,1,':'); cout << str << endl; // to be not to be(:) that is the question
it = [Link]([Link]()+5,','); // to be(,) not to be: that is the question
[Link] ([Link](),3,'.'); cout << str << endl; // to be, not to be: that is the question(...)
cout << str << endl;
[Link] (it+2,[Link](),[Link]()+3); cout << str << endl;
return 0; }
C++

Horizon

// (or )
135

#include <iostream>
#include <string>
using namespace std;
int main ()
{
string name ("John");
string family ("Smith");
name += " K. ";
// c-string
name += family;
// string
name += '\n';
// character
cout << name;
return 0;
}

C++

Horizon

136

Exercises
Define a class vector to hold 10 integers. Overload the operators
+, -, =, *. Overload the subscript operator [] to retrieve a specific
integer from the vector.
Define a class String which behaves as the char * string. Overload
the following operators : + (to implement the string
concatenation), *, ++ and the -- operators. Provide a constructor
that creates a string of the specified size, in the absence of the
specified size, some default size of 50 chars is taken.

C++

Horizon

137

Inheritance
A class inherits state and behavior from its superclass.
Inheritance provides a powerful and natural mechanism for
organizing and structuring software programs.
Example : mountain bikes, road bikes, and tandems are all
kinds of bicycles. In object-oriented terminology, mountain
bikes, road bikes, and tandems are all subclasses of the bicycle
class. Similarly, the bicycle class is the superclass of mountain
bikes, road bikes, and tandems.
Each subclass inherits state (in the form of variable
declarations) from the superclass. Mountain bikes, road bikes,
and tandems share some states: eg speed. Also, each subclass
inherits methods from the superclass. Mountain bikes, road
bikes, and tandems share some behaviors: braking and
changing pedaling speed, for example.
C++

Horizon

138

However, subclasses are not limited to the state and behaviors


provided to them by their superclass. Subclasses can add
variables and methods to the ones they inherit from the
superclass. Tandem bicycles have two seats and two sets of
handle bars; some mountain bikes have an additional chain
ring, giving them a lower gear ratio.
Subclasses can also override inherited methods and provide
specialized implementations for those methods. For example, if
you had a mountain bike with an additional chain ring, you
would override the "change gears" method so that the rider
could shift into those lower gears.
You are not limited to just one layer of inheritance. The
inheritance tree, or class hierarchy, can be as deep as needed.
Methods and variables are inherited down through the levels. In
general, the farther down in the hierarchy a class appears, the
more specialized its behavior.
C++

Horizon

139

Class hierarchies should reflect what the classes are, not how
they're implemented. If we implemented a tricycle class, it
might be convenient to make it a subclass of the bicycle class
both tricycles and bicycles have a current speed and cadence
but because a tricycle is not a bicycle, it's unwise to publicly
tie the two classes together. It could confuse users, make the
tricycle class have methods (such as "change gears") that it
doesn't need, and make updating or improving the tricycle class
difficult.
Inheritance offers the following benefits:
Subclasses provide specialized behaviors from the basis of
common elements provided by the superclass. Through the
use of inheritance, programmers can reuse the code in the
superclass many times.
C++

Horizon

140

Programmers can implement superclasses called abstract


classes that define common behaviors. The abstract
superclass defines and may partially implement the
behavior, but much of the class is undefined and
unimplemented. Other programmers fill in the details with
specialized subclasses.

C++

Horizon

141

Provides for the reusability of code


One class can be derived from another
The class that inherits from another is the derived class
The class inherited from is the base class
An object of newly derived class is also an object of the base
class

C++

Horizon

142

B1

D
single inheritance

B2

D1

multiple inheritance

D2

D3

hierarchical inheritance

B
BD1

DB

BD2
D

D
multilevel inheritance

hybrid inheritance

Various Forms of Inheritance


C++

Horizon

143

Single Inheritance
Example :
class Base
{
int intVar;
public:
int i;
void funcB(unsigned x) { /* code */ }
};
class Derived : public Base
{
public:
void funcD(unsigned x) { /* code */ }
// belongs to the derived class
};
C++

Horizon

144

Member Accessibility
The members of a class can have the following visibility modes :
private : the default mode
visibility limited within class only
protected : visible within class
visible also within the subclass as private member
public : visible everywhere
class X {
private : //accessible to members and friends only
protected : //accessible to members and friends and
//to members and friends of derived classes only
public : //accessible to the general public
};
C++

Horizon

145

Derivation Modes
A derived class can be created by inheriting the base class in the
following modes :
private
protected
public

The default mode of derivation is private.


class der-class-name : visibility mode base-class-name
{
// mems of derived class
}

C++

Horizon

146

The following table shows the visibility of the inherited members


depending on the derivation mode.

Base
Derived class visibility
class
private
protected
public
visibility derivation
derivation
derivation
private
not inherited not inherited not inherited
protected private

protected

protected

public

protected

public

C++

private

Horizon

147

Multiple Inheritance
Syntax is as follows :
class D : visibility B1, visibility B2,
{
// mems of D
};

C++

Horizon

148

Virtual Base Classes


For the following example :
A1

A2

B1

B2
D

D inherits the properties from the following classes :


B1
B2
A1 through B1
A2 through B2
C++

Horizon

149

In case B1 and B2 have the same parent as shown in the following


figure :
grand parent

parent#2

parent#1

D
D1 inherits the properties of class grandparent through parent#1
as well as parent#2.
This is an ambiguous situation.
C++

Horizon

150

class G {
public :
int i ;
};
class P1:public G {
};
class P2:public G {
};
class D: public P1, public P2 {
};
main()
{
D d1 ;
cout<<d1.i ; // error due to ambiguity
}
C++

Horizon

151

It is essential to declare the common base class as a virtual base


class as shown below :
class G {
// mems of G
};
class P1: virtual public G {
};
class P2: public virtual G {
};
class D: public P1, public P2 {
};
This ensures that only one copy of the parent class G is available
in D.
C++

Horizon

152

Constructors In Derived Classes


As long as no base class constructor takes an argument, the
derived class need not have a constructor function.
If the base class contains at least one constructor with at least
one argument then it is compulsory for the derived class to have
a constructor and pass arguments to base class constructors.
When an object of derived class is created the base constructor
is executed before the derived constructor.
Example :
class D : public A {} ;
constructor execution order : A, D

C++

Horizon

153

In multiple inheritance, the base class constructors are executed


in the order in which the base classes appear in the declaration
of the derived class.
Example :
class D : public A1, public A2, public A3 {} ;
constructor execution order : A1, A2, A3, D
In case of multilevel inheritance the constructors are executed in
the order of inheritance.
Example :
class B : public A {} ;
class D : public B {} ;
constructor execution order : A, B, D
C++

Horizon

154

The constructors of virtual base classes are invoked before any


non virtual base class constructors.
Example :
class D : public A, virtual public B {} ;
execution order : B, A, D
The derived class must pass the initial values to the base class
constructors.
It does so for only its immediate parents.
The derived class constructors receive the entire list of
arguments and pass them to the base constructors in the order
in which they are declared in the base class.
C++

Horizon

155

Example :
class B1 {
int
i1, j1 ;
public :
B1(int x, int y) {
i1 = x, j1 = y ;
cout<<"B1:"<<i1<<" "<<j1<<"\n" ; }
};
class B2 {
int
i2, j2 ;
public :
B2(int x, int y) {
i2 = x, j2 = y ;
cout<<"B2:"<<i2<<" "<<j2<<"\n" ; }
};
C++

Horizon

156

class D : public B1, public B2 {


public :
D(int a, int b, int c):B2(c, a), B1(b, c)
{
cout<<"derived\n" ;
}
};
main()
{
D obj(1,2,3) ;
}
Output :
B1 : 2 3
B2 : 3 1
derived
C++

Horizon

157

class gp {
public :

gp(int a, int b) {cout<<a<<" "<<b<<endl ;} } ;

class p1 : virtual public gp {


public : p1(int x) : gp(1, 2) {cout<<"p1:"<<x<<"\n" ;} } ;
class p2 : virtual public gp {
public : p2(int x) : gp(12, 22) {cout<<"p2:"<<x<<"\n" ;} } ;
class ch : public p1, public p2 {
public : ch() : p1(6), p2(7), gp(3, 4) {cout<<"ch\n" ;} } ;
class gc : public ch {
public : gc() : gp(78, 672) {} } ;
main() { ch

chobj ;

gc

gcobj ;}

In this case the ch class passes arguments to its non immediate parent
constructor. This is because, when ch object is created, neither p1 nor p2
can do the argument passing to gp.
C++

Horizon

158

Hence :
First, virtual base classes are created before non-virtual base classes, which
ensures all bases get created before their derived classes.
Second, note that the p1 and p2 constructors still have calls to the gp constructor.
If we are creating an instance of ch, these constructor calls are simply ignored
because ch is responsible for creating the gp, not p1 or p2.
However, if we were to create an instance of p1 or p2, the virtual keyword is
ignored, those constructor calls would be used, and normal inheritance rules
apply.
Third, if a class inherits one or more classes that have virtual parents, the most
derived class is responsible for constructing the virtual base class. In this case,
ch (or gc) inherits p1 and p2, both of which have a gp virtual base class. ch (or
gc) , the most derived class, is responsible for creation of gp.

C++

Horizon

159

Initialization List in the Constructor Function :


Example :
class XYZ {
int a ;
int b ;
public :
XYZ(int i, int j) : a(i), b(2+j){ }
XYZ(int i) : b ( a+1 ) , a ( 3*i ) { }
};
main( ) {
XYZ
obj1(2, 3) ;
XYZobj2(6) ;
}

This assigns the value 2 to a and 5 to b for obj1 and 18 to a and 19


to b for obj2.
a can not be given in terms of b because data members are
initialized in the order in which they are created which is the
same as the order in which they are declared.
C++

Horizon

160

Containing Classes
An object can be a collection of many other objects.
Thus members of a class can be objects of some other classes.
Following are
Containership :

the

differences

Inheritance :
provides the is a
relationship between the
related classes
derived class object is
an extended base class
object
C++

between

Inheritance

and

Containership :
provides the has a
relationship between the
related classes
container class object
has a property displayed
by the contained class.
Horizon

161

Constructor Invocation Rules for


Container Classes
First all those member are created which are themselves
objects of other class.
The ordinary members are created afterwards.
Constructors of the member objects are executed before the
class constructor.
They are executed in the same order as the order in which
they are declared.
The arguments to the member objects constructor are passed
by the main class constructor just as in the case of
inheritance.
C++

Horizon

162

class mem {
int i_mem ; char
c_mem ;
public :
mem(int i, char c) : i_mem(i), c_mem(c) {cout<<"constr of mem\n" ;}
void disp( )
{cout<<"\ni_mem :::"<<i_mem<< c_mem :::"<<c_mem<<endl<<endl ;}} ;
class container {
int i_con ; char c_con ; mem mem_con ;
public :
container(int i, char c) : i_con(i), c_con(c), mem_con(i+10, c+10)
{cout<<"constr of con\n" ;}
void disp( ) {
cout<<"i_con :::"<<i_con<< c_con :::"<<c_con ;
mem_con.disp() ; } } ;
main( ) { container c1(10, 'A') ; [Link]() ;}

C++

Output :
constr of mem
constr of con
i_con ::: 10 c_con ::: A
i_mem ::: 20 c_mem ::: K

Horizon

163

Destructor Invocation Rules


The order of destruction is just the reverse of the order of
construction, i.e., the first constructed is the last destroyed.

C++

Horizon

164

Final class in C++


Class which Can't be inherited by other class, that class is called final class.

In C++ final class has to be logically created.


This can be done in two ways :
1) Object of the final class will be on heap
class final2
{
public:
static final2* Create() { return (new final2()) ; }
static void Des(final2 *p) {delete p ;}
private: ~final2() {}
};
int main() {
final2 *f ;
f = final2::Create() ; // Object only on Heap
final2::Des(f) ;
}
class child : public final2 {public: child(){ }
};
//Error will come because child class can not inherit final2 class - destructor of
the final2 class is private.
C++

Horizon

165

1) Object of the final class will be on stack


class temp{
private: ~temp( ) {cout << temp destr\n ;}
friend class Final ; // Due to friend , Final class can use private member functions of
// temp class
};
class Final: virtual public temp {
// Define all data members and functions as you want
public:
Final( ) { }
~Final( ) {cout << Final destr\n ; }
};
class Child : public Final {
public:
Child( ){ }
~Child( ) { }
};

Now this final class can't be inherited by other class because temp class is inherited
virtually by Final class. So when Child constructor is called, then first temp
constructor will be called. By Child constructor, we are calling temp
constructor. Child class can not call temp class's private destructor because
Child is not a friend of temp. Complier sees this as a violation of rules.
C++

Horizon

166

Pointers
Pointers to objects can be declared and initialized in just the
same way as pointers to ordinary variables.
They can also be initialized by using the new operator.
Example :
class C {
int i ;
public :
C(int x) : i(x) { } C() : i(9) {}
void f( ) { }
};
main( ) {
C *p1 = new C(9) ;
C o;
C *p2 = &o ;
}
C++

Horizon

167

Object pointers can be used to access the members using the


arrow operator.
*ptr can be used with the same meaning. Thus in the previous
example :
(*p1).f( ) is valid.

C++

Horizon

168

this Pointer
this is a pointer to that very object on which the
function is invoked.
Example :
class C {
int
i;
public :
C(int i)
{ this->i = i ; }
void disp( ) { cout<<i<<"\n" ; }
};
main( ) {
C obj(10) ;
[Link]() ;
}
C++

Horizon

169

Accessing Derived Class Objects


Through Base Pointers
A base class pointer can be used to point to a derived class
object.
If the base class does not contain any virtual functions then the
members referred by using such a pointer are those belonging to
the base class.

C++

Horizon

170

Class Conversion

An object of a derived class can be used as if it were an object of


its base class
Example :
class Base{..};
class Derived : public Base{.};
void main(void)
{
Derived d;
Base b;
b = d; // class conversion
}
An object of the base class cannot be used as an object of a
derived class
C++

Horizon

171

Overriding
A derived class can define a member with the same name as a
base class member
Referring to its name in the derived class, accesses the
member in the derived class
class Base {
int i;
public:
Base(int x){ i = x;} // constructor
};
class Derived :: public Base{
int i;
public:
Derived(int x){i = x};// Derived :: i
void CalculateTotal(void){int total = i + Base :: i; }
};
C++

Horizon

172

Exercises
Create the class relationships for the following fig :
Qualification

Staff

Teacher

Salary
C++

Typist

Regular
Horizon

Officer

Casual
173

Create two more classes Student and College. The College class
maintains lists of the teachers on a per subject basis. The listfunctions are to be used from a LinkedList class. Use the Teacher
class from the previous question. The Student class provides with
functions selectTeacher(subject, College) which allows him to
select a teacher for a specific subject. This function uses the
dispTeacherDetails(subject) function of the College class to see
the list of name and qualification of the teacher.

C++

Horizon

174

Input/Output Operations

C++

Horizon

175

Streams I/O Library


I/O library include file : <iostream>
<stdio.h> I/O function are still supported by C++
Problem with I/O of C
printf , scanf etc cannot be overloaded
New format specifiers for user defined types cannot be
added
Lack of type checking
Note : There are many independent implementations of the
stream I/O library and the set of facilities described here
is only a subset of the actual library.
C++

Horizon

176

ios

istream

ostream

iostream

C++

Horizon

177

Inserters
cout is a predefined output stream attached to the standard
output device
<< sends character to the output stream
The text string on the right is stored in the left stream
#include <iostream.h>
int main()
{ cout << Hello World ! }
Same precedence as the standard left shift operator
cout << x + y << \n ; // OK
cout << x & y << \n ; //Error
/* & has lower precedence than << */
cout << (x & y) << \n ; Horizon
// OK
C++

178

cerr is a predefined error output stream attached to the


standard error device.

C++

Horizon

179

Stream Extraction
Fetches data from an input stream
The >> (right shift) operator is overloaded as the extraction
operator
cin is associated with the standard input device
Three types of extractors
integral
floating point
character
C++

Horizon

180

All extractors skip leading white spaces


Integral extractors
Read input characters until any that cannot be part of the type
123x456 is read as 123 with input pointer at x
Floating point extractors
Read input characters until any that cannot be part of the type
123e-4x5 is read as 123.0e-4 with input pointer at x
Character extractor
Reads the text character in the input stream skipping leading
white spaces
char * or string extractors read all input characters, skipping
leading white spaces, upto the next white space
This string is read as This
C++

Horizon

181

Multiple data items can be read in a single statement by


chaining operators together.
Example :
void main(void) {
char c ; int i ; float f;
char * buf[30];
cin >> c >> i >> f ;
}
void main(void) {
int i ; char c ; double
cin>>i>>c>>d ;
cout<<i<<endl ;
cout<<c<<endl ;
cout<<d<<endl ;
}

C++

d;

INPUT : 23x1.2
OUTPUT : 23
X
1.2
Horizon

182

I/O Formatting

Special methods are defined for formatting stream objects.


The width method specifies I/O width
For cin , only the specified numbers of characters are read
For cout , the output is displayed right justified in a field of
the specified width
If the length of input is greater than the current width , the
entire value is displayed for cout
Example :
char buf[21];
[Link](20); //only 20 characters read at a time
cin >> buf ;
int x = 1;
[Link](5);
cout << x ; /* x is displayed right justified in a field
five characters long */
C++

Horizon

183

The precision method sets the number of digits after the decimal
point
Involved when a float or double is displayed
Invoked with or without an int argument
Example :
void main(void) {
float pi = 3.14159 ;
[Link](3);
cout << pi ; }
Output : 3.14

C++

Horizon

184

The fill method sets the character used for padding extra space
when calling width
<space> is default fill character
Invoked only if the value set using width is greater than the
length of the inserted value
Example :
void main ( ) {
int x = 10 ;
[Link](0);
[Link](5);
cout<<x ; }
Output : 00010

C++

Horizon

185

Format Flags
Streams recognize flags to control format of input and output
left , right , internal
Only one of these may be set at any time
If left is set , inserted data is left justified
If internal is set , the sign of a numeric is left justified and
the value is right justified
Extra space in a field of set width is filled with the fill
character
If two of these are unset , the third is automatically set
float pi = 3.14159 ;
[Link](3) ;
[Link](8) ;
[Link](#) ;
[Link](ios::left) ;
cout<<pi ;
C++

OUTPUT :
3.14####

Horizon

186

dec , oct , hex


Only one of these may be set at any time
These control the base in which numbers are displayed
On extraction, the integral values are assumed and
interpreted to be in the set format
dec is set by default
showbase
Prefaces integral insertions with the base indicators used
with C++ constants
If hex is set , 0x is inserted in front of any integral
insertion and if oct is set then 0is inserted
This flag is not set by default
showpos
A + sign is inserted before any integral insertion
Remains unset by default
C++

Horizon

187

uppercase
All letters in numeric insertions will be converted to upper
case
Unset by default
showpoint
Forces the display of trailing zeros and decimal points in
float and double insertion
Unset by default
scientific , fixed
If scientific is set , floating point values are inserted using
scientific notation
One digit before the decimal point , precision digits after it ,
an e and the exponent value are present for the scientific
notation
If fixed is set , the value is inserted using decimal notation ,
with precision digits following the dicimal point
By default , scientific notation is used when the exponent is
less than -4 or greater than precision
C++

Horizon

188

unitbuf
The stream is flushed after every insertion
The flag is unset by default
stdio
Flushes the stdout and stderr devices defined in the stdio.h
Unset by default
Flags are stored as bits in a long member of every stream
Flags are set, unset and read by the following stream methods
long flags( )
returns the current format flags
long setf(long f)
sets the format flags to f
returns the previous flag value
long unsetf(long f)
unsets the flags that are set in f
returns the previous flag value
C++

Horizon

189

The bit values for the flags are members of an unnamed


enumerated type defined in the ios class
Flags can be ored (|) together to set/unset several flags in one
statement

C++

Horizon

190

Example :
#include <iostream.h>
void main ( )
{
double pi = 3.1415927 ;
int x = 1234 ;
// set new flags
[Link]( ios :: hex | ios :: showbase | ios :: uppercase | ios ::
scientific) ;
cout << x= << x <<pi =<< pi << endl;
//reset to original flag values
[Link](ios :: hex | ios :: showbase | ios :: uppercase | ios ::
scientific);
}

C++

Horizon

191

Manipulators
Manipulators
Change the format flags and values of a stream
Are set in the stream itself
Example :
int x = 1 , y = 2 ;
// sets the width
cout << setw(5) << x << setw(6) << y;
Predefined manipulator :
hex , dec ,oct
change the base of inserted or extracted integral values
The default for stream in dec
Example :
int i = 24 ; cout<<hex<<i<<endl ;
ios
Extract white space characters
endl
Inserts newline character
C++

Horizon

192

ends
Inserts a NULL character
Usually used to terminate a string
flush
Forces all insertions in the stream to be physically written to
the appropriate device
setfill(char f)
Changes the fill character to f
The default fill character is <space>
setw(int w)
change the field width to w
Is valid only for text insertion
Default field width is 0

C++

Horizon

193

setprecision(int p)
Sets the precision for floating point insertions to p
The default precision is 6
setiosflags(long f)
Sets the flags that are set in f
resetiosflags(long f)
Unsets the flags set in f
Header files
Include iostream.h and iomanip.h

C++

Horizon

194

Other input streams function


tie(ostream)
Attaches an output stream to an input stream
Output stream is flushed before extractions on the input
stream
[Link](cout) ; // flushes cout before cin
[Link](0) ; // unties cin from cout
ignore(int i)
Unconditionally ignores the next i characters for cin
[Link](5);
peek( )
The next character in the input stream can be looked at
without actually fetching i
char ch = [Link]()
C++

Horizon

195

putback(char ch)
Returns the last character that has been fetched to the input
buffer
An error may occur if the stream cannot accept the putback
character
get( )
Reads the next character from the input stream
char ch = [Link]( );
get() is overloaded with other version
get(char *str, int len, char delim = \n)
Fetches characters from the input stream into the array str
fetching is stopped if the len characters have been fetched
Fetching is also stopped if delim character is encountered
Next read occurs at the delimiter
C++

Horizon

196

get(char &ch)
Fetches the next character in the stream and stores it in ch
getline(char *str, int len, char delim = \n)
similar to get(char *, int, char)
Extracts the terminator also
Next read occurs after the delimiter
put(char ch)
A single character is written to an output stream without
translation

C++

Horizon

197

C++ Stream Classes


Declared in iostream.h
Stream classes for console operations are :
ios (General input/output stream class)
Contains basic facilities that are used by all other input
and output classes
It also contains a pointer to a buffer object (streambuf
object)
Declares constants and functions that are necessary for
handling formatted input and output operations
istream (Input stream)
Inherits the property of ios class
Declares input function such as get(),getline() and read()
Contains overloaded extraction operator >>
C++

Horizon

198

ostream (Output stream)


Inherits the property of ios class
Declares output function such as put() and write()
Contains overloaded insertion operator <<
iostream (Input/output stream)
Inherits the property of ios , istream and ostream class
through multiple inheritance and thus contains all the
input and output function
streambuf
Provides an interface to physical devices through buffers
It acts as a base for filebuf class used in files

C++

Horizon

199

Classes for File Operation


C++ I/O system contains set of file stream classes in fstream.h
Includes
filebuf
Its purpose is to set the file buffers to read and write
Also contains open() and close() method
fstreambase
Provides operations common to the file streams
Serves as base for fstream,ifstream and ofstream
Contains open() and close() method

C++

Horizon

200

ifstream class
Provides input operations
Contains open() with default input mode
Inherits the functions get(),getline(),read(),seekg() and
tellg() from istream
ofstream class
Provides output operations
Contains open() with default output mode
Inherits the functions put(),seekp(),write() and tellp()
from ostream
fstream class
Provides support for simultaneous input and output
operations
Contains open()
Inherits the functions from istream and ostream classes
through iostream
C++

Horizon

201

Opening A File
For opening a file
Create the file stream object
Link the file stream with filename
Two ways to open file
Using constructor function of the class
Create a file stream object to manage the stream using
appropriate class
Initialize the file object with the desired filename
Example :
ofstream outfile([Link]) ;
This statement opens the file [Link] and attaches it to
output stream outfile
This method is more appropriate when we use only one
file in the stream
C++

Horizon

202

Using the member function open() of the class


Create a file stream object to manage the stream using
appropriate class
Call open() method of stream object with the desired
filename
Example :
ofstream outfile ;
// creates stream
[Link]([Link]) ; // connects
This statement opens the file [Link] and attaches it
to output stream outfile
This method is used when we want to manage multiple
files using one stream object.

C++

Horizon

203

open() member function can take one OR two arguments


open(filename , filemode)
filename , specifies the file to be opened
filemode , specifies the purpose for which file is opened
Prototype for open() contains default values for filemode
argument
ios::in for ifstream functions meaning open for reading only
ios::out for ofstream functions meaning open for writing only

C++

Horizon

204

File mode constants are defined in the class ios


Filemode parameter can take one or more filemode constants
ios::app
Appends to end of file
ios::ate
Go to end of file on opening
ios::in
Open file for reading only
ios::nocreate Open fails if file does not exists
ios::noreplace Open fails if file already exists
ios::out
Open file for writing only
ios::trunc
Delete content of file if it exists

C++

Horizon

205

File Pointers & Manipulations


Each file has two file pointers associated with it
Input pointer (get pointer)
Output pointer (put pointer)
Input pointer is used for reading the content from file
Output pointer is used for writing to the file
Pointer advances automatically on each input/output operation
File stream classes provide functions for file pointer
manipulation

C++

Horizon

206

Functions for manipulating get pointer :


seekg(offset , refposition)
Moves get pointer to the specified location.
Parameter offset represents no of bytes the file pointer is to be
moved from the location specified by the parameter refposition
refposition can be ios::beg,ios::cur or ios::end
tellg()
Gives the current position of get pointer
Functions for manipulating put pointer :
seekp(offset , refposition)
Moves put pointer to the specified location.
Parameter offset represents no of bytes the file pointer is to be
moved from the location specified by the parameter refposition
refposition can be ios::beg,ios::cur or ios::end
tellp()
Gives the current position of put pointer
C++

Horizon

207

A simple example :
#include <string.h>
#include <iostream> #include <fstream>
using namespace std ;
main() {
char name[30] ; float

cost ;

ofstream out("TEST") ;
cout<<"Enter name:" ; cin>>name ; out<<name<<endl ;
cout<<"\nEnter cost:" ; cin>>cost ; out<<cost<<"\n" ;
[Link]() ;
strcpy(name, "") ;

cost = 0 ;

ifstream in("TEST") ;
in>>name ; in>>cost ;
cout<<"\nName : "<<name ;
cout<<"\nCost : "<<cost ;
}
C++

Horizon

208

Binary read, write to files : (The binary format is more accurate for storing
numbers and always faster for saving data as there are no conversions involved in
the process.)
#include <string.h> #include <iostream> #include <fstream>
class MyClass {
int intMem ; char chMem ; char chArr[5] ;
public :
int pubInt ; MyClass() {}
MyClass(int i){ intMem = 1 ;chMem = 'w' ;strcpy(chArr, "good") ;
pubInt = 20 ;}
void f(){} friend ostream &operator <<(ostream &s, MyClass c) ;} ;
ostream & operator << (ostream &s, MyClass c) {
s<<"\nIntMem:"<<[Link] ;s<<"\nCharMem:"<<[Link] ;
s<<"\nchArr : "<<[Link] ;s<<"\npubInt : "<<[Link]<<endl ;
return s ;}
main() {
MyClass
o1(10), o2 ; cout<<o1 ; cout<<o2 ;
fstream
file("TEST", ios::in|ios::out) ;
[Link]((char *)&o1, sizeof(o1)) ;
[Link](0,ios::beg) ; [Link]((char *)&o2, sizeof(o2)) ;
cout<<o1 ;
cout<<o2 ;
[Link](0,ios::end) ;
file<<o2 ; [Link]() ;}
C++

Horizon

209

Stream States
Every stream has a state associated with it.
Errors and non-standard conditions are handled by setting and
testing this state appropriately.
The stream state can be examined by operations on class ios.
Example :
fstream file(Temp) ;
[Link]() ; //end of file seen
[Link]() ; //next operation will fail
[Link]() ; //stream corrupted
[Link]() ; //next operation might succeed

C++

Horizon

210

String Stream
A stream can be attached to an array of characters in main memory.
A rough sketch of the available classes is given below :
istrstream
Contains open() with default input mode
Provides input operations
ostrstream
Contains open() with default output mode
Provides output operations
strstream
Contains open()
Provides support for simultaneous input and output operations
C++

Horizon

211

Example :
#include <string.h> #include <iostream> #include <strstream>
class MyClass {
int intMem ; char chMem ; char
chArr[5] ;
public :
int pubInt ; MyClass() {}
MyClass(int i){ intMem = 1 ;chMem = 'w' ;strcpy(chArr, "good") ;
pubInt = 20 ;}
void f(){} friend ostream &operator <<(ostream &s, MyClass c) ;} ;
ostream & operator << (ostream &s, MyClass c) {
s<<"\nIntMem:"<<[Link] ;s<<"\nCharMem:"<<[Link] ;
s<<"\nchArr : "<<[Link] ;s<<"\npubInt : "<<[Link]<<endl ;
return s ;}
main() {
MyClass
o1(40), o2 ;
cout<<o1 ;
cout<<o2 ;
char *p = new char[50] ;
strstream
str(p, 50) ;
[Link]((char *)&o1, sizeof(o1)) ;
cout<<o1 ; cout<<o2 ;
[Link]((char *)&o2, sizeof(o2)) ;
cout<<o2 ;}
C++

Horizon

212

Exercises
First write a program that creates a file of floating point numbers in
binary format. Then write a program that reads this file of floating point
numbers, makes complex numbers out of pairs of numbers read, and
displays the complex numbers.
Write a miniaturestream I/O system that provides classes istream,
ostream ifstream, ofstream providing functions such as operator<<() and
operator>>() for integers and operations such as open() and close() for
files. Use exceptions, rather than, state variables to communicate error
conditions.
Write a class CpFileToFile which reads source and destination file names
and provides for a function for copying from source to destination. Also
overload subscript operator to start copying from character provided as
input to this operator function. The function must return number of
characters hence copied from source to destination.
C++

Horizon

213

Templates

C++

Horizon

214

Templates enable us to define generic classes or functions


Templates make it possible to use a single function or a class
definition for a variety of data types i.e., to define a family of
functions or classes.
Template is defined with a parameter that would be replaced by
specific data type at the time of actual use of class or function.
A template can be considered as a type of a macro.
Templates can be :
function templates or
class templates.
C++

Horizon

215

The need for template functions :


To find minimum of two numbers, depending on the data type
of the numbers, the functions have to be declared.
Thus if the numbers are of int type, a function as given below
is required :
int min(int a, int b) ;
For two float type numbers the following function is required :
float min(float a, float b) ;
That is, though the functionality remains the same, separate
functions are required for separate data types.
This repetition of code can be avoided by using template
functions.

C++

Horizon

216

Function Templates

Syntax :
template <class T>
return_type function_name(args_list)
{ }
Example :
template <class T>
void Swap(T &x1, T &x2) {
T temp = x1 ;
x1 = x2 ; x2 = temp ; }
main( ) {
int i = 10 , j = 80 ;
Swap(i, j) ;
char c = A , d = B ;
Swap(c, d) ;}
C++

Horizon

217

class A {
int a1, a2 ;
public : A(int x) : a1(x) , a2(2*x) { }
int f( ) {return a1 ;} } ;
class B {
char b1 ;
public : B(char x) : b1(x) { }
char f( ) {return b1 ;} } ;
template <class T1, class T2>
T2 anything(T1 a , T1 b, T2 c) {
return T2(a+b+c.f( ) ) ;
}
main( ) {
int x = 9 , y = 10 ;
char c = Z , d = A ; A a1(60) ; B b1(K) ;
A a_obj = anything (x , y, a1) ;
B b_obj = anything (c , d, b1) ;
}
C++

Horizon

218

Performance
The compiler does not compile any code when it encounters the
template function definition.
When the template function is invoked then at that point the
compiler generates a specific version of the template function
corresponding to the argument types.
Finally at this point compiler generates the function call code.
This it does every time the compiler comes across a call
corresponding to a template function.
Use of templates does not help save memory because all the
different versions of the function are ultimately generated.
C++

Horizon

219

The advantage is that the code can be written with the generic
version only.
Thus templates provide reuse of the source code in contrast to
inheritance and containership which provide reuse of the object
code.
Templates can significantly reduce source code size and
increase code flexibility without reducing type safety.

C++

Horizon

220

A template function may be overloaded either by template functions


or ordinary functions of its name.
The overloading resolution is accomplished as follows :
Call an ordinary function that has an exact match.
Call a template function that could be created with an exact
match.
Try normal overloading resolution to ordinary functions and call
the one that matches.
An error is generated if no match is found.
No automatic conversions are applied to arguments on template funcs.
Example :
template <class T> T max(T a, T b) {return a>b?a:b ;}
void f(int a, int b, char c, char d) {
int m1= max(a, b) ; //max(int a, int b)
char m2 = max(c, d) //max(char c, char d)
int m3 = max(a, c) } //error c is a char and can not be converted to int
C++

Horizon

221

Thus a template function can be overridden to perform a specific


processing for a particular data type.
Example :
template <class T>
void f(T a) {
cout<<"inside template "<<a<<endl ; }
void f(char c) {
cout<<"non template "<<c<<endl ; }
main()
{
f(10) ;
f('A') ;
f(10.8) ;
}

C++

Output :
inside template 10
non template A
inside template 10.8

Horizon

222

template <class T>


T max (T a, T b) {
cout<<"templ\n" ;
return a>b ?a:b ;
}
void main() {
int a = 90, b = 80 ;
charc = 'a', d = 'n' ;
cout<<max(a, b)<<endl ;
cout<<max(c, d)<<endl ;
cout<<max(a, c)<<endl ; // error : cannot generate max(int, char)
}
But if the following is added :
int max (int a, int b) {
cout<<specl\n" ;
return a>b ?a:b ;
}
the first and the last function calls are resolved to the special version of the code.
C++

Horizon

223

Each template argument of a function template must affect the type


of the function by affecting at least one input argument type of
functions generated from the template.
This ensures that functions can be selected and generated based on
their arguments.
Example :
template<class T> void f1(T) ;
// fine
template<class T> void f2(T*) ;
// fine
template<class T> T f3(int) ;
// error
template<class T, class C> void f4(T t) ;
// error
template<class T> void f5(const T&, complex) ; // fine
template<class T> void f6(Vector<List<T>>) ; // fine

C++

Horizon

224

class A {int
a1, a2 ;
public : A(int x) : a1(x) , a2(2*x) { }
int f( ) {return a1 ;}} ;
template <class T1, class T2>
T2 anything(T1 a , T1 b, T2 c) {return T2(a+b+c.f( ) ) ;}
char anything(char b) { return b ; }
char anything(int a, int b, char c) { return 'a' ; }
main( ) {
int
x = 9, y = 10 ;
long p = 10, q = 11 ;
char c = 'Z' , d = 'A' ;
A
a1(60) ;
A a_obj = anything (p, q, a1) ;
cout<<anything('q') ;
cout<<anything(1, 2, 'q') ;
}
C++

Horizon

225

Class Templates

Example :
template <class T>
class stack {
T * arr ; int top ;
public : stack(int size ) {arr = new T[size] ; top = -1 ;}
void push(T t) ;
T pop( ) ; } ;

Syntax :
template <class T>
class class_name{ } ;

template <class T>


void stack <T> :: push(T t) { }
template <class T>
T stack <T>::pop( ) { }

T may be any data type:


built in
user defined
-structures
-classes

main( ) {
stack <int> st_int(10) ;
stack <char>
st_char(20) ; }

the keywords class and typename in a template parameter declaration


C++

Horizon

226

In the previous example, T is the template parameter and int or char (used at the
time of stack object creation) are the template arguments.
To use the default value of a template parameter, the corresponding template
argument must be omitted :
template <class T = int>
class stack {
T * arr ; int top ;
public : stack(int size ) {
arr = new T[size] ;
top = -1 ;
cout<<sizeof(T)<<"\n" ;
}
void push(T t) ;
T pop( ) ; } ;
template <class T> void stack <T> :: push(T t) { }

Output :
4
1

template <class T> T stack <T>::pop( ) { }


main( ) {
stack <> st_int(10) ;
stack <char>
st_char(20) ;
// this would generate an error -- stack var(8) ;
}
C++

Horizon

227

Class template can take default arguments.


The values of these arguments then become compile time constants
for that particular instantiation of the template.
template <class T, int def = 10>
class stack {
T * arr ;
int top ;
public :
stack(int size = def) {
cout<<size<<endl ;
arr = new T[size] ; top = -1 ;}
void push(T t) { }
T pop( ) { } } ;
main( ) {
stack <int>
st_int(20) ;
stack <char>
st_char ;
stack <char, 30>
st_char1 ; }

Output :
20
10
30

A new template can be inherited from an existing one.


It is a good practice to debug a particular template as a
function / class with specific data types.
C++

Horizon

228

Templates and multiple-filed projects


From the point of view of the compiler, templates are not normal

functions or classes.
They are compiled on demand, meaning that the code of a template
function is not compiled until an instantiation with specific template
arguments is required.
At that moment, when an instantiation is required, the compiler
generates a function specifically for those arguments from the
template.
For large code, it is usual to split the code of a program in different
source code files.
In these cases, the interface and implementation are generally
separated.
Taking a library of functions as example, the interface generally
consists of declarations of the prototypes of all the functions that can
be called.
C++

Horizon

229

These are generally declared in a "header file" with a .h extension,

and the implementation (the definition of these functions) is in an


independent file with c++ code.
Because templates are compiled when required, this forces a
restriction for multi-file projects: the implementation
(definition) of a template class or function must be in the same
file as its declaration. That means that we cannot separate the
interface in a separate header file, and that we must include
both interface and implementation in any file that uses the
templates.
Since no code is generated until a template is instantiated when
required, compilers are prepared to allow the inclusion more
than once of the same template file with both declarations and
definitions in a project without generating linkage errors.
C++

Horizon

230

Friends and Templates


A friend function of a template is not implicitly a template function.
Example :
template <class T> class task{
//
friend void next_time() ;
friend task<T> * preempt(task <T>*) ;
friend task * prmt(task *) ; // error
//
};
The function next_time is a friend to all task classes.
The function preemt is an appropraitely typed function for the specific
version of the class task.
The function prmt is wrongly declared because there is no type task,
but only specific template types like task<int>, task<record>, etc.
C++

Horizon

231

When a non-template class declares a template function as a friend, it


does so for a specific version of the template function.
Example :
class a {
int ai ;
template <class t>friend void func(t) ;
public :
a():ai(99){}
};
template <class T>
void func(T i) {
a obj ;

cout<<"func::"<<[Link]<<"\n" ;

}
main() {
int i ;
func(i) ;
func(99.9) ;

C++

Horizon

232

Static Members / Functions and


Templates
Each template class or function generated from a template has its own
copies of any static variables.
Example :
template <class T> class X {
static T s ;
//
};
X<int> aa ; X<char *> bb ;
Here X<int> has a static member s of type int and X<char *> has a
static member s of type char*.

C++

Horizon

233

Inheritance for Template Classes


The following code shows how can a template base class be used to
create a derived class :
template <class T>
class stack {
T * arr ; int top ;
public : stack(int size) {
cout<<size<<endl ; arr = new T[size] ; top = -1 ; }
void push(T t) { }
T pop( ) { }
};
template <class T1, class T>
class sp_stack : public stack<T> {
public : sp_stack() : stack<T>(99) {}
void f(T1 t1, T t2) {cout <<t1<<" "<<t2<<endl ;} } ;
void main( ) {
stack <char> st_char1(30) ;
sp_stack <int, double> spint ;
int i = 320 ;double d= 1.2 ;
spint.f(i, d) ; }
C++

Horizon

234

The following code shows handling of default arguments while


extension of a template base class :
template <class T, int def = 90>
class stack { T * arr ; int top ;
public : stack(int size = def) {
cout<<size<<endl ; arr = new T[size] ; top = -1 ; }
void push(T t) { }
T pop( ) { } } ;
template <class T1, class T, int def1 = 10>
class sp_stack1 : public stack<T, def1> {
public : void f(T1 t1, T t2) {cout <<t1<<" "<<t2<<endl ;} } ;
template <class T1, class T>
class sp_stack2 : public stack<T> {
public : void f(T1 t1, T t2) {cout <<t1<<" "<<t2<<endl ;} } ;
void main( ) {
stack <int> st_int(20) ; stack <char, 30>
st_char1 ;
sp_stack1 <int, double>
spint ;
sp_stack1 <char, double, 33>
spchar ;
sp_stack2<char, char> cpCharChar ;
int i = 320 ;double d= 1.2 ;
spint.f(i, d) ; }
C++

Horizon

Output :
20
30
10
33
90
320 1.2

235

Derivation and Templates


Two types generated from a common template are different and have no
inheritance relationship, unless their template arguments are identical.
This feature is depicted in the following code :
template <class T> class stack { } ;
class shape { } ;
class circle : public shape { } ;
void main( ) {
stack<int> sint1 ; stack<int> sint2 ; stack<double> sdouble ;
sint1 = sint2 ;
sint1 = sdouble ; // error
stack<circle *> cirPtr1 ; stack<circle *>
cirPtr1 = cirPtr2 ;
shPtr1 = cirPtr1 ; // error
circle
*cptr ;
shptr = cptr ;
}

C++

shape

cirPtr2 ; stack<shape *> shPtr1 ;

*shptr ;
Horizon

236

Class Template and Partial Template Specialization


Class Template Specialization :
In many cases when working with templates, it is required that one generic
version is written for all possible data types and leave it at that - every vector may
be implemented in exactly the same way.
The idea of template specialization is to override the default template
implementation to handle a particular type in a different way.
Example :
While most vectors might be implemented as arrays of the given type, you might
decide to save some memory and implement vectors of bools as a vector of
integers with each bit corresponding to one entry in the vector.
So two separate vector classes would be required :
The first class might look like as follows :

C++

template <class T>


class vector {
private:
T* vec_data; // the data is stored as block of dynamically allocated memory
int length; // number of elements used
int vec_size; // actual size of vec_data
};
Horizon

237

But when it comes to bools, it might not be required to do this because most
systems are going to use 8 or 16 or 32 bits for each boolean type even though all
that's required is a single bit.
So the boolean vector can be made to look a little bit different by representing
the data as an array of integers whose bits can be manually manipulated.
To do this, it is still needed to specify that something similar to a template is
being used, but this time the list of template parameters will be empty :
template <>
and the class name is followed by the specialized type, so that the template
would look like this :
template <>
class vector <bool> {
private:
unsigned int *vector_data;
int length;
int size; };
It is perfectly reasonable if the specialized version of the vector class has a
different interface (set of public methods) than the generic vector class although they're both vector templates, they don't share any interface or any
code.
C++

Horizon

238

Thus the idea of C++ class template specialization is similar to function template
overloading.
This can make the template code for certain data types to be fixed.
Once the template is specialized, all the member functions should be declared and
defined for the specific data type.
Example :
template<>
class MyQueue<double> {
std::vector<double> data;
public : void Add(double const &); void Remove(); void Print();
};
template <> void MyQueue<double> ::Add(double const &d) {
data.push_back(d);
}

C++

Horizon

239

Partial Template Specialization :


Partial template specialization allows the programmer to specialize only some
arguments of a class template, as opposed to explicit specialization, where all
the template arguments are provided.
Example :
template <class A, class B>
class Pair {
private: A a; B b;
public:
Pair(A aa, B bb):a(aa),b(bb) {}
void display() {
cout << a << ' ' << b << endl; }
};

To use this class, the template parameters can be declared explicitly when an
instance of the class is declared :
Pair<double,double> doubledouble(1.2,2.3);
[Link]();
C++

Horizon

240

Heres a partial template specialization of the Pair class. It has special code
when the second parameter is an int :
template <class A>
class Pair<A, int> {
private: A a; int b;
public:
Pair(A aa, int bb):a(aa),b(bb*bb) {}
void display() {
cout << a << ' ' << b << endl;
}
};

Using the partially-specialized template is no different from using the original


template :
Pair<double,int> doubleint(2.2,3);
[Link]();

C++

Horizon

241

Exercises
1) Write a template class to implement a stack.

Write a template class to create a map to hold key-value pairs.


The key as well as the value could be objects of any class.
Overload the subscript operator to take the key as an input and
return the value as the output. The value returned should be
the one corresponding to the one stored against the key provided
as input to the function.

C++

Horizon

242

Use this map class to hold a map of teacherName and phNo in


the College class. Let the Student class have the following
methods :
class Student {

public : void dispTeacherDetails(subject, College) { }


void findTeacher(subject , College) {

dispTeacherDetails(subject, College) ;
// select teacher name
[Link](teachName) ;
getTeachPhNo(char * teachName) ;

}
};

Now the College class has a method findPhNo(char *) which


uses the overloaded subscript operator that returns the teachers
phNo.
C++

Horizon

243

Exception Handling

C++

Horizon

244

Exceptions refer to unusual conditions in the program.


The purpose of exception handling is to provide means to
detect and report errors such that necessary action can be taken.
This mechanism involves the following tasks :
Find the problem hit the exception
Inform that an exception has occurred throw the exception
Receive the error information catch the exception
Take corrective actions - handle the exception
Keywords used :
throw
try
catch

C++

Horizon

245

Exceptions could be
synchronous :- errors such as
out-of-range index
falling short of memory
Inability to open a file
asynchronous :- caused by events beyond the control of the
program, eg, keyboard interrupts
The exception handling mechanism is designed to handle the
synchronous exceptions.

C++

Horizon

246

class stack {
int
arr[2], top ;
public : stack( ){top = -1 ;}
class full{ } ; class empty{ } ;
void push(int i) {
if (top == 1) throw full() ;
top++ ;arr[top] = i; }
int pop( ) {
if(top == -1) throw empty() ;
else {top-- ; return 1 ;} }
};
main( ) {
stack s ;
try{ [Link](1) ;cout<<"1\n" ;
[Link](2) ;cout<<"2\n" ;
[Link](3) ;cout<<"3\n" ;
} catch(stack::full f){cout<<"full\n" ;} }
C++

Horizon

OUTPUT : 1
2
full

247

The push and pop functions throw the objects of the relevant classes.
Following statements summarize the working of the exception
handling mechanism :
Code executes normally outside the try block.
When a statement in a try block causes an error in a member
function then that member function throws an exception.
Control then transfers to the catch block following the try block.
Once the catch block is executed the control jumps to the first
statement after the catch block.
If for an exception there is no matching exception handler on the
call chain where the exception is generated, the program will be
terminated.
C++
Horizon
248

If an exception is thrown before the constructor completes


execution then the associated destructor will not be called for
that object.
When an exception is thrown, a destructor is automatically
called for any object that was created by the code up to that
point in the try block.
Exceptions impose an overhead in terms of program size and
(when an exception occurs) in time. So we should not try to
overuse it.

C++

Horizon

249

An exception is caught by specifying its type.


What is thrown is not a type but an object.
If we need to transmit extra information from the throw point to the
handler, we can do so putting data into that object.
Example :
class Vector {
int sz ; int *p ;
public : class Range {
public : int index ;
Range(int i) : index(i) { } } ;
Vector (int s) : sz(s) { /* initialize p */}
int & operator[ ] (int i) {
if (o <= i && i < sz) return p[i] ;
throw Range(i) ; }} ;
void f(Vector &v) {
//
try { do_something(v) ;}
catch (Vector :: Range r) {cerr<<bad index ::<<[Link]<<endl ;}
};
C++

Horizon

250

For templates we have a choice when naming an exception.


Each class generated can have its own exception class as shown
below :
run once with ai.f(10) ; ad.f(1) ;

template <class T> class Allocator {


and once with ai.f(1) ; ad.f(10) ;
public : class Exhausted { } ;
T * get( ) { }
void f(int i) { cout<<"in f\n" ; if(i == 10) throw Exhausted() ;} } ;
void f(Allocator <int> &ai, Allocator <double> &ad) {
try { ai.f(10) ; ad.f(1) ; }
catch (Allocator <int> :: Exhausted) { cout<<"int ver\n" ; }
catch (Allocator <double>:: Exhausted) { cout<<"double ver\n" ; }
}
void main() {
Allocator<int> aInt ;

Allocator<double> aDbl ;

f(aInt, aDbl) ;
}
C++

Horizon

251

Alternately, an exception can be common to all classes generated


from the template :
class Allocator_Exhausted { } ;
template <class T> class Allocator {
public :
T * get( ) { }
void f(int i) { cout<<"in f\n" ;if(i == 10) throw Allocator_Exhausted() ;}
};
void f(Allocator <int> &ai, Allocator <double> &ad) {
try { ai.f(1) ; ad.f(10) ; }
catch (Allocator_Exhausted) { cout<<"exc\n" ; }
}
void main() {
Allocator<int> aInt ;

Allocator<double> aDbl ;

f(aInt, aDbl) ;
}
C++

Horizon

252

The following example shows that if an exception is thrown


before the constructor completes execution then the associated
destructor will not be called for that object.
class Cl {
public : class exc{} ;
Cl( ) { cout<<"in constr\n" ;
throw exc() ;
cout<<"exception thrown\n" ; }
~Cl( ) { cout<<"in destr\n" ; }

OUTPUT
in constr
exception caught

};

main( )
{ try
{ Cl obj ; }
catch(Cl::exc E) {cout<<"exception caught" ;}
}

C++

Horizon

253

The following example shows that when an exception is thrown, a


destructor is automatically called for any object that was created by the
code up to that point in the try block.
class Cl {
public : class exc{} ;
Cl( ) { cout<<"in constr\n" ;
throw exc() ;
cout<<"exception thrown\n" ; }
~Cl( ) { cout<<"in destr\n" ; } } ;
class CC {
public : CC() {cout<<"constr of CC\n" ;}
~CC() {cout<<"destr of CC\n" ;} } ;

OUTPUT
constr of CC
in constr
destr of CC
exception caught

main( ) {
try
{ CC o1 ;
Cl obj ; }
catch(Cl::exc E) {cout<<"exception caught" ;}
}
C++

Horizon

254

class full { public: void disp() {cout<<"full\n" ;}} ;


class subFull: public full{ } ;
class stack {
int
arr[2], top ;
public :
stack( ) {top = -1 ;}
void push (int i){
if (top == 1) throw subFull() ;
else {top++ ;arr[top] = i;}}
int pop( ) {
if(top == -1) throw empty() ;
else {top-- ; return 1 ;} }
};
This exception is caught in the
main( ){ stack s ;
first catch block i.e., by the
try {
[Link](1) ;cout<<"1" ;
base exception handler
[Link](2) ;cout<<"2" ;
[Link](3) ;cout<<"3" ;}
catch(full f){ [Link]();}
catch(subFull sf){cout<<"in subfull\n" ;}
}
C++

Horizon

255

class full { public: void disp() {cout<<"full\n" ;}} ;


class BigNum { public: void disp() {cout<<"tooooooooo big num\n" ;}} ;
class stack {
int
arr[2], top ;
public : stack( ){top = -1 ;}
void push(int i) {
if (i > 100) throw BigNum() ;
if (top == 1) throw full() ;
else {top++ ;arr[top] = i;} } } ;
void f1(stack s) {
try{
[Link](101) ;cout<<"1" ;
[Link](2) ;cout<<"2" ;
[Link](3) ;cout<<"3" ;
}
catch(BigNum big){[Link]();}}
main( ) {

push throws two exceptions


one of them is handled in main
and the other is handled in f1()

stack
s;
try { f1(s) ;}
catch(full f){ [Link]();}

}
C++

Horizon

256

class full { public: void disp() {cout<<"full\n" ;}} ;


class BigNum { public: void disp() {cout<<"tooooooooo big num\n" ;}} ;
class stack { int
arr[2], top ;
public : stack( ){top = -1 ;}
try inside another catch
class empty{ } ;
void push(int i){
if (i > 100) throw BigNum() ;
if (top == 1) throw full() ;
else {top++ ;arr[top] = i;}}
int pop( ) { if(top == -1) throw empty() ;
else {top-- ; return 1 ;} }} ;
void f1(stack &s) {
[Link](1) ;cout<<"1\n" ; [Link](2) ;cout<<"2\n" ;
[Link](3) ;cout<<"3\n" ; [Link]() ;cout<<"4\n" ;}
void main( ){
stack
s;
try {
f1(s) ; }
catch(full f) {
[Link]();
try{
[Link]() ;cout<<"4\n" ;
[Link](300) ;cout<<"3\n" ;}
catch(BigNum big){[Link]();}
catch(stack :: empty){} }}
C++

Horizon

257

Exercises

Create the following classes :


Corresponding to every user there exists a physical file in the disk
which has the same name as the user account no ( eg, u01 for acc no
1). This file contains the balance in savings account and the total
amount in fixed deposit and the no of fixed deposits.
There is a second file per user (eg, fd01 for
acc no 1). This file contains the period,
amount and fdNo for each fd for that
user.

Account
Name
AccountNo

Savings

FixedDeposit

Balance

Period
Amount

There is a master file (MASTER)


containing the user name and the account
no sorted on account nos.
Write program through which a new
account can be created, an existing one
deleted or accessed for viewing.
C++

Horizon

258

The program handles 10 maximum [Link] get incremented


initially till 10 and then the unused ones are reused lying between 1 to
10.
When an existing account is deleted, its user name is marked as
XXXX across the name.
Throw exception if user tries to withdraw more than (balance-1000)
for savings or (more than amt / before period) for fixed deposits.
A user can have any number of fixed deposits.

C++

Horizon

259

Write a function that searches a binary tree of nodes based on a


char * field for a match. If a node containing hello is found,
find(hello) will return a pointer to that [Link] exception to
indicate not found.
Define a class Int that acts exactly like the built-in type int except
that it throws exceptions rather than overflow or underflow.

C++

Horizon

260

Dynamic Polymorphism And


VTABLE

C++

Horizon

261

Dynamic Polymorphism
Dynamic polymorphism is achieved by the use of Virtual
Functions.
How is dynamic polymorphism achieved ?
Pointer to base class is used to refer to a derived class object.
The function with the same name (say test) in the base and the
derived class is preceded by the keyword virtual in the base
class.
When a base class pointer is referring to a derived class object
then if the function test is invoked using such a pointer then the
derived class version is executed.
If in the base class this function is not preceded by the keyword
virtual then it is the base class version of the function is invoked.
C++

Horizon

262

Example :
class A {
public : virtual void f( ) { cout<<ff in AAAA\n ; }
void p( ) { cout<<pp in AAAA\n ;}
};
class B : public A {
public : void f( ) { cout<<ff in BBBB\n ; }
void p( ) { cout<<pp in BBBB\n ;}
};
main( )
{ B derived_obj ; A base_obj ;
A * base_ptr = & base_obj ;
base_ptr->f( ) ; base_ptr->p( ) ; // base versions of f( ) & p( ) called
base_ptr = & derived_obj ;
base_ptr->f( ) ; // derived versions of f( ) called
base_ptr->p( ) ; // base versions of p( ) called
}

C++

Horizon

263

Example :
class base {
public : virtual void f() {cout<<"base\n" ;} } ;
class der_b : public base {
public : void f() {cout<<"der1\n" ;} } ;
class der_d : public der_b {
public : void f() {cout<<"der2\n" ;} } ;
void main() {
base *bptr ; der_b dObj ; der_d ddObj ;
bptr = &dObj ; bptr->f() ; //der 1
bptr = &ddObj ; bptr->f() ;
//der 2
der_b *dptr = &ddObj ;
dptr->f() ;
//der 2
}

C++

Horizon

264

How use of virtual functions results in dynamic polymorphism?


In case the base class pointer is pointing to an object of a derived
class and a virtual function of the base class is invoked through
such a pointer then :
the compiler selects the function to be called based on the
contents of the pointer and not on the type of the pointer
but the compiler does not know the contents of ptr because ptr
gets initialized to the derived address only at run time
so it is not known at compile time the class to which the
function belongs
so the decision of which version of the function is to be called,
is deferred till the program is running.
C++

Horizon

265

Hence it is also known as late binding.


Even references can be used to get the same results.

C++

Horizon

266

Rules for Virtual Functions


The virtual functions must be members of some class.
They cannot be static members
A virtual function can be a friend of another class.
A virtual function in a base class must be defined, even though
it may not be used.
The prototypes of the base class version of a virtual function
and all the derived class versions must be identical.
Virtual constructors are not possible but virtual destructors are
possible.
C++

Horizon

267

A base class pointer can point to a derived class object but the
reverse is not true.
When a base pointer points to a derived class, incrementing or
decrementing it does not make it point to the next object of the
derived class. It is incremented or decremented only relative to
its base type.
It is not necessary to redefine a virtual function in the derived
classes. If not redefined in the derived classes the base version
is invoked.

C++

Horizon

268

Pure Virtual Functions


Pure virtual functions are defined as follows :
virtual return_type function_name(args_list) = 0 ;
A pure virtual function is declared in a base class if the
function has no definition relative to the base class.
If there exists a pure virtual function in a base class then it is
compulsory that each derived class does one of the following
things :
either the function is re-declared a pure virtual function
in the derived class
or the derived class provides a definition for the pure
virtual function.
A class containing a pure virtual function is an abstract class
and hence can not be used to create objects.
C++

Horizon

269

Abstract Classes
Abstract classes are those that can not be used for creating
objects.
To ensure that such classes are not used for object creation
the functions of the class can be declared as pure virtual.
The main objective of abstract classes is to provide some
common traits to the derived classes and to create a base
pointer required for achieving runtime polymorphism.
A class is abstract if it has at least one pure virtual function.
An abstract class may not be used as an argument type, as a
function return type, or as the type of an explicit conversion.
Pointers and references to an abstract class can be declared.
C++

Horizon

270

VTABLES

C++

Horizon

271

class A {
int i ;
public : virtual void f() {cout<<"AAA\n" ;}
};
class B {
int i ;
public : void f() {cout<<"BBBB\n" ;}
};
class C {
public : void f() {cout<<"CCCC\n" ;}
};
class D { } ;
main() {
A a;B b;C c;D d;
cout<<sizeof(A)<<endl<<sizeof(B)<<endl<<sizeof(C)<<endl<<
sizeof(D)<<endl ;
}
C++

Horizon

272

The size of class B is 4 : size of int data type.


The size of class A is 8 : (size of int) + (size of a void pointer)
The sizes of class C and D are 1 : so that objects of these classes
have non-zero sizes. (There can not be an array of zero sized
objects)

C++

Horizon

273

With virtual functions in a class the following is true :


The compiler creates a VTABLE for each class that contains
virtual functions and for the classes derived from it.
This VTABLE of a class contains addresses of the virtual
functions for that particular class.
If a derived class does not redefine a virtual function of the base
class then the compiler places the address of the base class version
itself in the VTABLE of the derived class.
The compiler adds a void pointer to an object of such base and
derived classes containing virtual functions.
This pointer, called the vpointer (VPTR) points to the classs
VTABLE.
C++

Horizon

274

Whenever a virtual function is invoked using the base class


pointer, the compiler inserts the code to fetch the VPTR and to
look up the function address in the VTABLE.
This causes late binding to take place to invoke the correct
virtual function because the VPTR gets initialized at run-time.
When a virtual function is invoked on a base class pointer
containing the address of a derived class object then :
The compiler reads the contents of the base class pointer.
Through this the compiler reads the derived objects VPTR.
Through this VPTR the derived class VTABLE is accessed.
From this table address of function being invoked is fetched.
Using this address, function of derived class is accessed.

C++

Horizon

275

Other related issues :


It is important that no call to a virtual function is made before
the VPTR is initialized to point to the correct VTABLE.
The VPTR is automatically initialized in the constructor.
This is why the compiler adds a zero-argument constructor if
not provided in a class to initialize the VPTR if required.
All objects have their VPTR in the same place usually in the
beginning of the object. This makes extraction of VPTR easy.

C++

Horizon

276

class A {
public :
virtual void f( ) { cout <<f :: AAAA\n ; }
};
class B : public A {
public :
void f( ) { cout <<f :: BBBB\n ; }
virtual void g( ) { cout <<g :: BBBB\n ; }
};
main( )
{
B derived_obj ;
A * base_ptr = & derived_obj ;
base_ptr -> g( ) ;

//compilation error

}
C++

Horizon

277

This code generates a compilation error because g( ) is not a


member of class A.
Though the VTABLE contains both the functions f( ) and g( ), but
the compiler does not know what objects address is available in
the base_ptr.
So the compiler decision whether the member invoked is correct or
not is based on the type of base_ptr.
Once the code compiles successfully then only the VTABLES
come into picture for the virtual functions.

C++

base VTABLE

derived VTABLE

&base :: f( )

&derived :: f( )
&derived :: g( )
Horizon

278

If the type of the object pointed by the base pointer is known


during code generation then the following can be used :
((B *) base_ptr) -> g( ) ; //base address casted to derived address
Casting the derived address to base address is always safe.
The reverse is not true.

C++

Horizon

279

Object Slicing
class A {
public : virtual void f( ) { cout<<"AAAA\n" ;}
};
class B : public A {
public : void f( ) { cout<<"BBBB\n" ;}
};
main( ) {
A a;B
a=b;
a.f( ) ;
}

b;
Object b is sliced so that it becomes the smaller
object equivalent to a type copying only the
base portion of the object.
This code invokes the base version of f( ).

C++

Horizon

280

Invoking Virtual Functions From


Constructors/Destructors
Virtual functions can
constructor/destructor.

be

invoked

from

within

In this case it is the member function of the current class that gets
invoked, i.e. the virtual mechanism doesnt work and no
polymorphism is achieved.

see next slide for eg


C++

Horizon

281

class b {
public :
b() {cout<<"invoking f from base constr ::: " ;f() ;}
virtual void f() {cout <<"base\n" ;}
void g() {cout<<"invoking f from g ::: " ;f() ;}
};
class d : public b { int I ;
public :
d() {I = 90 ;cout<<"invoking f from der constr ::: " ;f() ;}
void f() {cout<<"der\n" ; I = 88 ;}
};
void main() {
b * p = new b ;
p->g() ;
cout<<"1-----\n" ;
p = new d ;
p->g() ;
}
C++

OUTPUT
invoking f from base constr ::: base
invoking f from g ::: base
1---invoking f from base constr ::: base
invoking f from der constr ::: der
invoking f from g ::: der

Horizon

282

Virtual Destructors

class A {
public :
A( ){cout<<"base cons\n" ;}
~A( ){cout<<"base destr\n" ;}
};
class B : public A {
public :
B( ){cout<<"der cons\n" ;}
~B( ){cout<<"der destr\n" ;}
};
main( ) {
A * ptr = new B ;
delete(ptr) ;
}
C++

Horizon

Output :
base cons
der cons
base destr

283

The object is not destroyed fully as the derived class destructor


is never invoked.
If we can force the invocation of the derived destructor then the
base destructor is anyway automatically called.
This can be done by declaring the base destructor as virtual.
Virtual destructors are possible because :
During destruction the type of the object is already known and
the VPTR already initialized.
This is not the case with the constructor.

C++

Horizon

284

Pure virtual destructors can be created but they must be


provided with the body.
This is because all destructors in a class hierarchy get invoked
during destruction of an object.
Thus in the previous code if the base destructor is preceded by
the keyword virtual then the derived destructor is also invoked.
The output would be as follows :
base cons
der cons
der destr
base destr

C++

Horizon

285

Dependencies within a Class


Hierarchy

Consider the following code :

#include <iostream.h>
class base {
public :
virtual void f() {cout<<"f of base\n" ;}
void g() {f() ;} } ;
class der1 : public base {
public :
void f() {cout<<"f of der1\n" ;} } ;
class der2 : public base {
public :
void f() {cout<<"f of der2\n" ;}} ;
void main() {
base * ptr = new base ; ptr->g() ;
ptr = new der1 ; ptr->g() ;
ptr = new der2 ; ptr->g() ; }
C++

Horizon

Output :
f of base
f of der1
f of der2

286

Thus if the member function of a base class itself calls one of the
classs virtual functions, then the base class depends on its derived
classes for its own implementation.
The requirement for such a code would be visible in the following
example.
Consider the following integer buffer class :
class buffer {
// . . .
void put(int) ;
int get() ;} ;

The overflow and the underflow implementation could be


hardwired into the class, but such a code would have limited
usefulness.
If the put() and get() functions call virtual functions overflow()
and underflow() respectively, different types of buffers can be
tailored to suit a variety of needs.
The following piece of code depicts this.
C++

Horizon

287

class buffer {
// . . .
virtual int overflow(int) ;
virtual int underflow() ;
void put(int) ; // call overflow(int) if buffer is full
int get() ;} ; // call underflow(int) if buffer is empty
class circular_buffer : public buffer {
// . . .
int overflow(int) ; // wrap around when buffer is full
int underflow() ; } ;
class expanding_buffer : public buffer {
// . . .
virtual int overflow(int) ; // increase buffer size when full
virtual int underflow() ; } ;
C++

Horizon

288

Run-time Type Information


RTTI is a mechanism that allows the type of an object in an
inheritance hierarchy to be determined during program
execution.
RTTI was added to the C++ language because many vendors
of class libraries were implementing this functionality
themselves. This caused incompatibilities between libraries.
Thus, it became obvious that support for run-time type
information was needed at the language level.
The concept applies to pointers as well as references.

C++

Horizon

289

THE NEED FOR RTTI: ( a simple example )


class shape { } ;
class circle : public shape { } ;
class rectangle : public shape { } ;
main( )
{
shape * sh [5] ;
//some elements of sh point to circle object
//the remaining point to rectangle object
}
If we need to change the colour of all the circles only then we need to
downcast the base pointer back to that of the correct derived class.
C++

Horizon

290

There are three main C++ language elements to run-time type information:
The typeid operator - used for identifying the exact type of an object
This operator returns the run-time type of an object. If the operand provided
to the typeid operator is the name of a type, the operator returns an object that
identifies it. If the operand provided is an expression, typeid returns the type
of the object that the expression denotes.
The dynamic_cast operator - used for conversion of polymorphic types.
This operator combines type-checking and casting in one operation. It checks
whether the requested cast is valid, and performs the cast only if it is valid.
The type_info class - used to hold the type information returned by the typeid
operator.
This class describes the RTTI available, and is used to define the type returned
by the typeid operator. This class provides to users the possibility of shaping
and extending RTTI to suit their own needs. This ability is of most interest to
implementers of object I/O systems such as debuggers or database systems.
C++

Horizon

291

usage of typeid

- a simple example

class shape {} ;
class circle : public shape {} ; // ALL THE MEMBERS OF THE THREE CLASSES
class rectangle : public shape {} ; // ARE NON VIRTUAL
void main ( ) {
shape *sh[8] ; int i ;
for (i = 0; i < 8; i++) {
if (i % 2 == 0)
sh[i] = new circle() ;
else
sh[i] = new rectangle() ;
}
for (i = 0; i < 8; i++)
cout<<endl<<typeid(sh[i]).name()<<" :: "<<typeid(*sh[i]).name() ;
}

OUTPUT:
class shape * : : class shape
class shape * : : class shape
class shape * : : class shape
C++

total 8 times
Horizon

292

usage of typeid

contd

include typeinfo.h

class shape {public : virtual void ar ( ){}} ;


class circle : public shape {public : void ar ( ){}} ;
class rectangle : public shape {public : void ar ( ){}} ;
void main ( ) {
shape *sh[8] ; int i ;
for (i = 0; i < 8; i++) {
if (i % 2 == 0)
sh[i] = new circle() ;
else
sh[i] = new rectangle() ;
}
for (i = 0; i < 8; i++)
cout<<endl<<typeid(sh[i]).name()<<" :: "<<typeid(*sh[i]).name() ;
}
OUTPUT:
class shape * : : class circle
class shape * : : class rectangle
class shape * : : class circle and so on
C++

Horizon

293

The example emphasizes the following :


RTTI should be used only with polymorphic classes i.e. those
which have a virtual function in the base class. (as in the second
example)
In the absence of polymorphism the static type information is
used. (as in the first example)
typeid ( ) can be used with built-in types also.
cout<<endl<<typeid(45).name() ; //output -: int

C++

Horizon

294

usage of dynamic_cast
class shape {public : virtual void ar ( ){}} ;
class circle : public shape {public : void ar ( ){}} ;
class rectangle : public shape {public : void ar ( ){}} ;
void main ( ) {
shape *sh[8] ; int i ;
for (i = 0; i < 8; i++) {
if (i % 2 == 0) sh[i] = new circle() ;
else
sh[i] = new rectangle() ;
}
circle * cir_ptr ;
for (i = 0; i < 8; i++)
{
if(cir_ptr = dynamic_cast<circle *>(sh[i])) // dynamic_cast successful
cout<<endl<<"dynamic_cast :: circle" ;
else
// dynamic-cast unsuccessful
cout<<endl<<"dynamic_cast :: rectangle" ;
}
}

C++

Horizon

295

another example of dynamic_cast (complete the code and check)


class employee {
public:
virtual int salary();
};

NOTE :

In the above program, dynamic casts


are needed only if the base class
employee and its derived classes are
not available to users (as in part of a
class manager : public employee {
library where it is undesirable to
public:
modify the source code). Otherwise,
int salary();
adding new virtual functions and
virtual int bonus();
providing derived classes with
};
specialized definitions for those
functions is a better way to solve
void calc (employee *pe) {
this problem.
// employee salary calculation
if (manager *pm = dynamic_cast<manager*>(pe)) {
// use manager::bonus()
}
else {
// use employee's member functions
}
C++

Horizon

296

Upcasting with dynamic_cast

Means moving a pointer up a class

heirarchy.
class grandP {public : virtual void testF() {cout<<"grandP f\n" ;}} ;
class parent : public grandP {
public : void parF( ) {}
virtual void testF( ) {cout<<"parent f\n" ;}} ;
class child : public parent {
public : void testF( ) {cout<<"child f\n" ;}} ;
main( ){
grandP * ptr ; parent par ;
ptr = &par ; ptr->testF() ;//parent ver invoked
//dynamic polymorphism
grandP g = *ptr ;
//object slicing
[Link]() ; //grandP version invoked
grandP *gPtrTemp = dynamic_cast<grandP *>(ptr) ;
gPtrTemp->testF() ; //parent
parent *pPtrTemp = dynamic_cast<parent *>(ptr) ;
pPtrTemp->testF() ; //parent
pPtrTemp->parF() ;
child
chd ;
gPtrTemp = dynamic_cast<grandP *>(&chd) ;
gPtrTemp->testF() ;} //child
C++

Horizon

297

In this example :
gPtrTemp->parF() can not be invoked because:
gPtrTemp is now casted to the object of the base class.
Thus parF() function is not a member.
But the virtual function is still of the derived class only bec
it is accessed thru the vptr and the vtable
these get initialized at the time the object is created.
This type of conversion is called an upcast
It moves a pointer up a class hierarchy, from a derived class to a class
it is derived from.
An upcast is an implicit conversion.
C++

Horizon

298

While downcasting i.e., moving a pointer down the class heirarchy,


care must be taken that the casting is valid.
Following is erroneous :
class base { public : virtual void f(){cout<<"base\n";}} ;
class der1:public base { public :

void f() {cout<<"der1\n";}} ;

class der2:public base {


public : void f() {cout<<"der2\n";}
void g() {cout<<"g in der2\n" ;}} ;
main() {
base * bPtr = new der1() ;
der1 * d1Ptr = dynamic_cast<der1 *>(bPtr) ;
d1Ptr->f() ; //conversion allowed
der2 * d2Ptr = dynamic_cast<der2 *>(bPtr) ; // error
base b ;
d1Ptr = dynamic_cast<der1 *>(&b) ; //error
}

C++

Horizon

299

Other related operators :


static_cast (resolve at compile time)
reinterpret_cast
const_cast

C++

Horizon

300

Exercises

Create the following classes :


a. shape (the base class)
b. line, rectangle and myshape (derived from shape)
myshape draws a face as shown below :

Ultimately the program should be designed to draw the following :

You may use some graphics / screen functions for actual


implementations.

C++

Horizon

301

Develop
the functions writeToDisc(const Persistent &) and
readFromDisc(Persistent &).Create a class Persistent that contains
virtual functions save( ) and read( ) [define the interfaces for these
functions as required]. These member functions of Persistent class
would be invoked by the above functions.
Any class that needs to be written to / read from the disc provides its
own implementation of these functions.
Test this code for any two of your own classes.
Create the following classes with some basic functionalities
identified, and identify the relationships between the classes :
a. window
Develop a class based on these
b. scrollbar
classes that would generate the
c. Vert_scrollbar
following window :
d. Hori_scrollbar
e. window_with_scrollbars
f. Button
C++

Horizon

302

Interfaces
An interface :
defines a set of operations
the operation implementations may be missing
these implementations are provided by the classes
implementing the interfaces.
supports the inheritance features
these features are with respect to other interfaces only
provides the objects identity

C++

Horizon

303

Interfaces in C++ :
Interfaces are implemented in C++ as abstract base classes.
All methods are declared as pure virtual functions.
This abstract class thus can not be used for creating objects.
This interface (abstract class) is then inherited by the class that
wants to implement the interface.
The inherited class then has the responsibility to provide
implementations for the operations given in the interface.

C++

Horizon

304

An ideal interface :
presents a complete and coherent set of concepts to a user
is consistent over all parts of a component
does not reveal implementation details to a user
can be implemented in several ways
depends in limited and well-defined ways on other interfaces.

C++

Horizon

305

Namespaces
Namespace provides a scope to the visibility of a name for a
class, function, structure, union, variable etc.
C++ provides a single global namespace by default.
We can split this single global namespace into multiple namespaces
by using the keyword namespace.
Declarations that fall outside all namespaces remain members of
the global namespace.
A namespace definition can appear only at a global scope
void main( ) { namespace local { } }

This would generate an error.


C++

Horizon

306

namespace space1 {
class big {
public :
void f() {cout<<"space1\n" ;} } ;
}
namespace space2 {
class big {
public :
void f() {cout<<"space2\n" ;} } ;
}
void main()
{
space1 ::big b1 ;
b1.f() ;
space2 ::big b2 ;
b2.f() ;
}
C++

Horizon

307

namespace space1 {
class big {
public :
void f() {cout<<"space1\n" ;} } ;
}
namespace space2 {
class big {
public :
void f() {cout<<"space2\n" ;} } ;
}
void main()
{
{
using namespace space1 ;
big b1 ;
b1.f() ;
}
using namespace space2 ;
big b2 ;
b2.f() ;
C++
}

The curly braces specify the scope for


using namespace space1.
Otherwise after using namespace space2
both namespaces are used.

Horizon

308

#include <iostream.h>
void f() { cout<<"global f\n" ; }
void g() { cout<<"global g\n" ; }
namespace space1 {
namespace space2 { void g() {cout<<"sp1 :: sp2 :: g\n" ;} }
void f() {cout<<"function fun\n" ;}
class big { public : void f() {cout<<"space1\n" ;} } ;
}
namespace space2 {
class big { public : void f() {cout<<"space2\n" ;} } ;
}
void main() {
using namespace space1 ;
big b1 ;
b1.f() ;
space1::f() ; // Since this function is also present in the global namespace, the
// specific function has to be identified using scope resolution. Else
//
it generates an error.
::f() ; // Global f() executed.
//using namespace space1 :: space2 ;// This statement has no effect.
space1::space2::g() ;
C++
Horizon
309
}

A namespace definition can be continued over multiple header


files. Example :
// mylib1.h
namespace sp1 { void f( ) ; class c { } ;}
// mylib2.h
namespace sp1 { void g( ) ; class d { } ;}

The continuation of namespace after the initial definition is called


extension-namespace-definition.
Members of a namespace can be defined within (as shown in the
previous examples) or outside that namespace ( as shown below)
namespace space1
namespace space1 {
void f() ; // defined outside the namespace
class big {
public :
void f() {cout<<"space1\n" ;} } ; }

It is necessary that
the definition follows
the declaration.

void space1 :: f() {cout<<"function fun\n" ;}


C++

Horizon

310

A namespace can be given an alternate name (to prevent typing


long names) :
namespace space1 {
void f() ; }
namespace sp1=space1 ;
void sp1 :: f() {cout<<"function fun\n" ;}

A global namespace cannot be the same as any other global entity


name in a particular program.

C++

Horizon

311

Memory Management

C++

Horizon

312

C++ Memory Use


C++ program variables and objects may occupy memory that is
obtained in three different ways :
Static memory refers to memory allocated during compilation
examples are global data and static data
these exist when program is loaded until end of run
Automatic
memory

local variables and objects in each function or block


created on the stack on entry
destroyed (destructed) on exit

Dynamic
memory
(Free Store)

obtained from operating system, using new


allocated from the system free store
objects exist until end of run or delete

C++

Horizon

313

Static Store

class table {
public :
table(int i) {cout<<"table constr : "<<i<<"\n" ;} } ;
table tbl_1(20) ;
void f(int i) { static table tbl_2(i) ; }
Output : table constr : 20
main( ) {
main 1
cout<<"main 1\n" ;
table constr : 30
f (30) ; f(10) ;
main 2
cout<<"main 2\n" ; }

Here the constructor table :: table(int) is executed twice -: once


each for tbl_1 and tbl_2.
The destructor is also executed twice -: to destroy tbl_1 and
tbl_2 after exit from main( ).
Constructors for global static objects (eg : tbl_1) are executed in
an order in which the declarations occur. Destructors are called
in reverse order.
Constructors for local static objects (eg : tbl_2) are executed the
first time the thread of control passes through the objects
definition.
C++

Horizon

314

By allocating a global static object for a class with constructor


and/or destructor a programmer has a simple way of specifying
code to be executed before and/or after the call to main( ).
If a program is terminated using exit function the destructors for
constructed static objects are called. Thus exit( ) does not
terminate the program immediately.
If a program is terminated using abort function the destructors
for constructed static objects are not called.

C++

Horizon

315

#include <iostream.h>
class table {
public : table(int i) {cout<<"constr\n" ;}
~table() {cout<<"destr\n" ;}
};
table tbl_1(50) ;
void f(int i)
{
static table tbl_2(i) ;
}
main( )
{
cout<<"in main\n" ;
f (30) ;
f(20) ;
cout<<"programme terminates\n" ;
}
C++

OUTPUT
constr
in main
constr
programme terminates
destr
destr

Horizon

316

The C++ Free Storage


All dynamic memory requests are satisfied through an area of
memory called heap. These requests are made through the new
operator.
It is the responsibility of the programmer to return dynamically
allocated memory to the free pool, by using the delete operator.
new/delete operations take a lot of CPU time.
Ideally to every new there should be a matching delete.

C++

Horizon

317

new AND delete


In addition to allocating memory new also creates an object by
calling the objects constructor.
In addition to deallocating memory delete also destroys the
object by calling the objects destructor.
While allocating memory using new it is allocated from the free
store (the heap).
An object created using new exists until it is explicitly destroyed
using delete.
The expression delete p doesnt delete the pointer rather the
object pointed to by p (i.e., releases the memory held by p).

C++

Horizon

318

class jlt { int


i;
public : void f() {cout<<"\nfunc in jlt" ;} } ;
void main() {
jlt *p = new jlt ;
cout<<"\ndefore delete, p :: "<<p ;
delete(p) ;
cout<<"\nafter delete, p :: "<<p ;
}

Thus even after delete(p) is executed p still contains the same


address. Hence p still points to the same memory location which
should not be now accessed with the same meaning.
Worst is to re delete(p).
C++

Horizon

319

Taking Over Memory Management for a class by re-defining


new() and delete() operators.
The new and delete operators are used to allocate and deallocate
free store, respectively.
One can define own versions of new and delete for a class by
overloading them.
When new and delete operate on class objects, the class member
operator functions new and delete are called, if they have been
declared.

C++

Horizon

320

If a class object is created with the new operator, one of the


operator functions operator new() or operator new[]() (if they have
been declared) is called to create the object.
An operator new() or operator new[]() for a class is always a static
class member, even if it is not declared with the keyword static. It
has a return type void* and its first parameter must be the size of the
object type and have type std::size_t. It cannot be virtual.
If a class object is destroyed with the delete operator, the operator
function operator delete() or operator delete[]() (if they have been
declared) is called to destroy the object.
An operator delete() or operator delete[]() for a class is always a
static member, even if it is not declared with the keyword static.
Their first parameter must have type void* and have a return type
void. It cannot be virtual.
C++

Horizon

321

The delete operator destroys an object created by the new operator.


If delete is called for an object with a destructor, the destructor is
invoked before the object is deallocated.
If new and delete are called for a class object that does not declare
the operator functions new and delete, or they are called for a
nonclass object, the global operators new and delete are used.
The C++ operators for allocating and deallocating arrays of class
objects are operator new[ ]() and operator delete[ ]().

C++

Horizon

322

#include <iostream> #include <malloc.h> using namespace std ;


class MyClass { int mem ;
public : MyClass() { cout << "obj constr\n" ;}
void * operator new(size_t s) {cout<<"my new, size is :"<<s<<"\n" ;return malloc(s) ;}
void * operator new [](size_t s) {
OutPut :
cout<<"my new for arr, size is :"<<s<<"\n" ;
obj constr
return malloc(s) ; }
my new, size is :4
void operator delete(void * p) { cout<<"my delete\n" ;
free(p) ; }
obj constr
void operator delete [](void * p, size_t t) {
trying array
cout<<"my delete for arr, size is :"<<t<<"\n" ;
my new for arr, size is :32
free(p) ; }
obj constr
~MyClass() { cout << "obj destr\n" ;}
obj constr
};
obj constr
obj constr
void main() {
trying delete
MyClass
obj1 ;
obj destr
MyClass
* p1 = new MyClass ;
my delete
cout << "\ntrying array ...\n" ;
obj destr
MyClass
* p2 = new MyClass[7] ;
obj destr
cout<<"\ntrying delete ...\n" ;
obj destr
delete p1 ;
obj destr
delete[] p2 ;
my delete for arr, size is :4
}
obj destr
C++

Horizon

323

Thus new and delete can be summarized as follows:

new

-obtains memory from the system free store


-the object is then initialized
-the constructor is run
-returns a pointer to the dynamically created object

delete

-the destructor is run


-releases the memory to the operating system

C++

Horizon

324

Exercises

Write a template class to represent complex numbers of integers,


or doubles. Overload the +, - and * operators to handle the
functionalities for the template complex class.

Write a template class stack that provides for its own memory
management routines.

Define
the
classes
buffer,
circular_buffer
and
expanding_buffer as mentioned in slide#279. Implement them as
template classes and implement the overflow and underflow
conditions accordingly.

C++

Horizon

325

Standard Template Library


provides a library of reusable
components

STL is a C++ programming library that has been designed


to enable a C++ programmer to do generic programming
and is based on the extensive use of templates - also called
parameterized types.
C++

Horizon

326

Basic Terms :
CONTAINER CLASS :
a class that can contain objects, example : lists, sets, arrays
it provides a way to organize data in memory
the type of objects contained are of little interest to the definer of
the container class i.e., the type of the object contained itself is
an argument to the container class.
ALGORITHMS :
define computational procedures.
a broad range of fundamental algorithms including sorting,
searching, and transforming are defined.
they can be used with any container with sufficient functionality,
for example - random access instead of linear access.
C++

Horizon

327

ITERATORS :
provide a means of stepping through the items contained by a
container.
FUNCTIONS :
can be encapsulated inside an object for use by other
components.
ADAPTORS :
adapt a component to present a different interface - to define a
reverse iterator, or present a stack-like interface, for example.

C++

Horizon

328

The Standard Template Library provides a set of parameterized


container classes and other components, to which algorithms can
be applied in a generic way.
The library is structured so that any algorithm will work with
any container providing it meets certain specifications.
The STL contains five main categories of generic components.

C++

Horizon

329

How Components Work Together


Containers store objects of arbitrary types.
Containers are parametrized by allocators.
Allocators are objects which encapsulate information about the
memory model used. They provide memory primitives to handle
memory accesses uniformly.
Containers use allocators to do their memory accesses. A change
of the memory model used leads to a change of the allocator
object given as an argument to the container. This means, that on
the code level a container object is invariant under different
memory models.
An algorithm is a computation order. So, two algorithms should
differ in the computations done by them, not in the access method
used to read input data and write output data.
C++

Horizon

330

STL provides a uniform data access mechanism for its algorithms


- iterators. Different iterators provide different access modes.
Function objects are used in combination with algorithms to
encapsulate functions and operations to extend the algorithms'
utility.
Adaptors are interface mappings, they implement new objects
with different or enhanced functionality on the basis of existing
components.

C++

Horizon

331

Overview of STL components


Containers
Sequence containers
Sorted Associative Containers
Generic Algorithms
find, merge, search, copy, count, sort, accumulate
Iterators
Function Objects
Adaptors
Allocators
C++

Horizon

332

Containers
Containers are data structures that manage a collection of
elements and are responsible for the allocation and de-allocation
of those elements.
Containers typically have constructors and destructors along
with operations for inserting and deleting elements.
STL containers contain a minimal set of operations for creating,
copying, and destroying the container along with operations for
adding and removing elements.
There are no member functions for examining the elements in a
container or sorting them. Instead, algorithms have been
decoupled from the container and can only interact with a
container via traversal by an iterator.
C++

Horizon

333

The STL provides two categories of containers:


Sequence containers
store elements in sequential order
group a finite set of elements in a linear arrangement.
all sequence containers provide iterators
the STL includes class templates for vectors, lists, deques
Associative containers
store elements based on a key value
provide efficient retrieval of elements based on their key
the collection is maintained in order, based on a comparison
function object of type Compare
container size can vary at run-time, and their contents are
maintained in a sorted order
support functions such as insertion of elements and ranges of
elements, unique insertion, search by key and erasure of
elements or ranges
the STL provides class templates for maps, multimaps, sets,
and multisets.
C++
Horizon
334

vector :
contains a block of contiguous initialized elements
defines a dynamic array - an array that can grow during use (the
vector automatically resizes)
provides array-like fast random access
supports insertion and deletion at any point in array, this being a
linear time operation
provides constant time insertions and deletions at the end
supports the standard array-indexing syntax for accessing its
elements by overloading [ ] operator (random access iterator)
Thus a vector object can be indexed like an array and an element can
be accessed using the subscript notation.
C++

Horizon

335

Although vectors allow array-style indexing, their elements can be


also accessed through an iterator. The iterator is defined by
container classes.
To obtain an iterator for vector : vector <T>::iterator i
The template specification for vector:
template <class T, class Allocator=allocator <T> > class vector

where T is the type of data being stored and Allocator specifies the
allocator which defaults to the standard allocator

C++

Horizon

336

Constructors :
vector (const Allocator &a=Allocator() ) Constructs an empty vector
vector (size_type num, const T &val=T() , const Allocator &a=Allocator() )
Constructs a vector that has num elements with value val
vector (const vector <T, Allocator> &ob) vectors copy constructor.
template <class InIter>
vector (InIter start, InIter end, const Allocator &a=Allocator() )
Constructs a vector that contains the elements in the range specified by start and
end.

C++

Horizon

337

Some of the most commonly used member functions are:


iterator begin ()
iterator end ()
bool empty ()

Returns an iterator to the first element in the vector.


Returns an iterator to the end of the vector.
Returns true if the vector contains no elements.

iterator erase (iterator i) Removes the element pointed to by i. Returns an iterator to the
element after the one removed.
iterator erase (iterator start, iterator end) Removes the elements in range start to end. Returns
an iterator to the element after the one removed.
template <class InIter> void insert (iterator i, InIter start, InIter end) Inserts the sequence
defined by start and end immediately before the
element specified by i.
void pop_back ()
Removes the last element in the vector.
void push_back (const T &val) Adds an element with the value specified by val to the end of
the vector.
size_type size ()
Returns the number of elements currently in the
vector.

To use vector class include <vector>.


C++

Horizon

338

Deletion of the first element can be easily programmed on vector using


method [Link]([Link]()), but that kind of operation should be avoided
because it is very inefficient for long vectors since all of the elements
after the first position must be shifted over to fill the hole, it is a linear
time operation.

C++

Horizon

339

#include <vector> #include <string> #include <algorithm>


#include <assert.h> #include <iostream> using namespace std ;
template<class T>void print(vector<T> v) {
for(int i = 0; i < [Link](); i++)
cout<<v[i]<<"\t";
cout<<endl; }
main() {
vector<int> vi; vector<string> vs;
for(int i = 0; i < 20; i++) vi.push_back(i);
assert(![Link]()); print(vi);
cout<<"Changing values of elements in range 3 through 7...\n";
for(i = 3; i < 8; i++) vi[i] = 100; print(vi);
cout<<"Removing elements\n"; [Link](&vi[3], &vi[8]); print(vi);
vs.push_back("John"); vs.push_back("Tom"); vs.push_back("Jane");
vs.push_back("Anna");
print(vs);
cout<<"\nSorting elements...\n";
sort([Link](), [Link]()); print(vs);
cout<<"\nRemoving last element...\n";
C++

vs.pop_back();

Horizon

print(vs); }

340

lists :
supports bidirectional access, most often implemented as
doubly-linked list and may be traversed in either direction
insert and erase operations anywhere within the sequence take
place in constant time
manages allocation and deallocation automatically
fast random access is not supported provides linear time access
some generic algorithms require random access, hence these
operations are provided as member functions of the list class

C++

Horizon

341

The list class supports bi-directional iterator. Thus, the container


can be accessed through an iterator in both forward and reverse
direction.
To obtain an iterator for list : list <T>::iterator i
The template specification is :
template <class T, class Allocator=allocator <T> > class list
where T is the type of data being stored and Allocator specifies the allocator
which defaults to the standard allocator.

C++

Horizon

342

Constructors:
list (const Allocator &a=Allocator() ) Constructs an empty list
list (size_type num, const T &val=T(),const Allocator &a=Allocator() )
Constructs a list that has num elements with value val
list (const list <T, Allocator> &ob)

list's copy constructor.

template <class InIter>


list (InIter start, InIter end, const Allocator &a=Allocator() )
Constructs a list that contains the elements in the range specified by start and
end.
.

C++

Horizon

343

Some of the most commonly used member functions are:


iterator begin ()
iterator end ()
bool empty ()
reference back ()
reference front ()

Returns an iterator to the first element in the list.


Returns an iterator to the end of the list.
Returns true if the list contains no elements.
Returns a reference to the last element in the list
Returns a reference to the first element in the list

iterator erase (iterator i)


iterator erase (iterator start, iterator end)
iterator insert (iterator i, const T &val)
void insert (iterator i, size_type num, const T &val)
template <class InIter> void insert (iterator i, InIter start, InIter end)
void pop_back ()
Removes the last element in the list.
void pop_front ()
Removes the first element in the list
void push_back (const T &val)
void push_front (const T &val) Adds an element with value specified by val to front of list.
void remove (const T &val) Removes elements with the value val from the list
size_type size ()
Returns the number of elements currently in the
vector.
C++

Horizon

344

Some special member functions are:


void merge (list<T, Allocator>&ob)

void sort ()

Merges ordered list contained in ob with the


ordered invoking list. The result is ordered. After
the merge , the list contained in ob is empty
Sorts the list.

void splice (iterator i, list <T, Allocator> &ob) The contents of ob are inserted into the
invoking list at the location pointed by i. After the
splice, ob is empty
void splice (iterator i, list <T, Allocator> &ob, iterator start, iterator end)
The range defined by start and end is removed from ob and stred in the invoking list
beginning at the location pointed to by i.

C++

Horizon

345

#include <list> #include <string> #include <assert.h>


#include <iostream> using namespace std;
template<class T> void print(list<T> l) {
list<T>::iterator it = [Link](); //obtaining iterator
while(it != [Link]()) cout<<*it++<<"\t"; cout<<endl; }
main() { list<int> li; list<string> ls;
for(int i = 0; i < 20; i++) li.push_back(i);
print(li);
cout<<"Removing first 5 elements...\n";
for(i=0; i<5; i++) {
cout<<[Link]()<<" removed\n"; li.pop_front(); }
cout<<endl; print(li);
cout<<"Removing 7 and 12 from the list...\n";
[Link](7); [Link](12); print(li);
[Link](); assert([Link]());
ls.push_back("John");ls.push_front("Tom");
ls.push_back("Anna"); ls.push_front("John");
cout<<"\nSorting elements...\n"; [Link]();
print(ls);

print(ls);

cout<<"\nRemoving duplicate elements...\n";


[Link](); print(ls); }
C++

Horizon

346

deques.
is a a double-ended queue
supports random access
allows insert and erase operations in constant time at the head or
tail, and in linear time in the middle.
memory management is handled automatically.
has many similarities with vector but they differ in one
important respect: you can manipulate with both ends of deque
supports random access iterator and [ ] operator is overloaded
Thus a deque object can be indexed like an array, and an element
can be accessed using the subscript notation
also supports reverse iterator
C++

Horizon

347

To obtain an iterator for deque : deque <T>::iterator i


The template specification is :
template <class T, class Allocator=allocator <T> > class deque

where T is the type of data being stored and Allocator specifies


the allocator which defaults to the standard allocator.
Constructors :
deque (const Allocator &a=Allocator() ) Constructs an empty deque.
deque (size_type num, const T &val=T(), const Allocator &a=Allocator() )
Constructs a deque that has num elements with value val
deque (const deque <T, Allocator> &ob) deques copy constructor.
template <class InIter>
deque (InIter start, InIter end, const Allocator &a=Allocator() )
Constructs a deque that contains the elements in the range specified by start
and end.
C++

Horizon

348

Some of the most commonly used member functions are:


iterator begin ()
iterator end ()
bool empty ()

Returns an iterator to the first element in the deque.


Returns an iterator to the end of the deque.
Returns true if the list contains no elements.

reference front()
reference back ()

Returns a reference to the first element in the list


Returns a reference to the last element in the list

iterator erase (iterator i)


iterator erase (iterator start, iterator end)
iterator insert (iterator i, const T &val)
void insert (iterator i, size_type num, const T &val)
template <class InIter> void insert (iterator i, InIter start, InIter end)
void pop_back ()
void pop_front ()
void push_back (const T &val)
void push_front (const T &val)

Removes the last element in the deque.


Removes the first element in the deque.

size_type size ()

Returns the number of elements currently in the


vector.

C++

Horizon

349

#include <deque> #include <string> #include <algorithm>


#include <assert.h> #include <iostream> using namespace std;
template<class T> void print(deque<T> d) {
for(int i = 0; i < [Link](); i++) cout<<d[i]<<"\t";
cout<<endl; }
main() { deque<int> di; deque<string> ds;
for(int i = 0; i < 20; i++) di.push_back(i);
assert(![Link]()); print(di);
cout<<"Changing vals of elements in range 3 thru 7...\n";
for(i = 3; i < 8; i++) di[i] = 100;
print(di);
cout<<"Removing elements in range 1 through 7...\n";
for(i = 0; i < 8; i++) di.pop_front();
print(di);
[Link]();
ds.push_back("John"); ds.push_front("Tom");
ds.push_front("Jane"); ds.push_back("Anna");
assert(![Link]()); print(ds);
cout<<"\nSorting ...\n"; sort([Link](),[Link]());
print(ds);
cout<<"\nRemoving last element...\n"; ds.pop_back();
print(ds); }
C++

Horizon

350

Vectors are the most commonly used sequence containers. They


are sequence containers of choice when the fastest possible random
access is needed, and few if any insertions or deletions are required
at any point other than the end.
The array in C/C++ has one restriction: its size is fixed at compile
time. The vector class solves this problem by allocating memory
as needed. It defines a dynamic array - an array that can grow
during use.
Lists should be used in preference to other sequence containers
when frequent insertions and deletions are required in the middle of
sequences and there is little need to jump around randomly from
one position to another.
Deques are sequence containers of choice when fast random access
is needed, and if insertions or deletions are required at the
beginning and the end of the [Link] is perfect container to use
if you will be frequently moving from one end to the other, for
example, when rotating the contents of the container.
C++

Horizon

351

Associative Containers types :


set<T, Compare> supports unique keys, provides for fast retrieval of
the keys themselves.
multiset<T, Compare> allows equal keys, provides for fast retrieval of
the keys themselves.
map<Key, T, Compare> supports unique keys, provides for fast
retrieval of values of another type T base on the keys.
multimap<Key, T, Compare> supports unique keys, provides for fast
retrieval of values of another type T base on the keys.
Thus : Maps and multimaps allow arbitrary data to be associated with
each key.
Also, maps and sets only allow elements with unique keys
Multimaps and multisets may contain elements with duplicate
keys.
C++

Horizon

352

Maps and Multimaps :


The map class supports an associative container in which unique
keys are mapped with values.
A key is simply a name associated with a value.
Once a value has been stored, it can be retrieved by its key.
The power of a map is that a value can be looked up given its
key.
Example, a map could be defined that uses a persons name as
its key and stores that persons telephone number as its value.
Multimap is similar to map except that it allows duplicate
keys. Thus, one key can be used for more than one value.

C++

Horizon

353

The map class supports bi-directional iterators.


Thus, the container can be accessed through an iterator in both
forward and reverse direction.
Random access operations are not supported.
The map class overloads the assignment operator =. It also defines
comparison operators: ==, <, <=, !=, >, >=
Key/value pairs are stored in a map as objects of type pair.
A pair contains two fields:
Key_type
Value_type

C++

first;
// contains the key
second. // contains the value associated with the key

Horizon

354

The data type of the pair must match those of the map into which
the pair are being inserted.
The iterator type defined by map points to objects of type
pair<Key, T>.
To obtain an iterator for map : map <Key, T>::iterator i
The template specification is :
template <class Key, class T, class Comp=less<Key>,
class Allocator=allocator <T> > class map

where Key is the data type of keys, T is the data type of the value
being stored (mapped), Comp is the function that compares two
keys, and Allocator specifies the allocator which defaults to the
standard allocator.

C++

Horizon

355

Constructors :
map (const Comp &cmpfn=Comp(),const Allocator &a=Allocator() )
Constructs an empty map
map (const map <Key, T, Comp, Allocator> &ob)
map's copy constructor.
template <class InIter>
map (InIter start, InIter end, const Comp &cmpfn=Comp(), const
Allocator &a=Allocator() )
Constructs a map that contains the elements in the range specified by
start and end.

C++

Horizon

356

Some of the most commonly used member functions are:


iterator begin ()
Returns an iterator to the first element in the map.
iterator end ()
Returns an iterator to the end of the map.
bool empty ()
Returns true if the map contains no elements.
iterator find (const key_type &k) Returns an iterator to specified key. If the key is not found, then
an iterator to the end of the map is returned.
iterator erase (iterator i)
iterator erase (iterator start, iterator end)
size_type erase (const key_type &k) Removes from map elements that have keys with value k.
iterator insert (iterator i, const T &val)
template <class InIter> void insert (InIter start, InIter end) Inserts a range of elements defined
by start and end immediately before the element
specified by i.
pair<iterator, bool> insert (const value_type &val) Inserts val into the map only if it is not
already there. If the element is inserted returns
pair<iterator, true>, otherwise, pair<iterator, false>
is returned
size_type size ()
Returns the number of elements currently in the map.
reference operator[ ](const key_type &k) Returns reference to value associated with key
specified by k. If this element does not exist, it is
C++
Horizon
357
inserted.

#include<iostream> #include <map> #include<string>


using namespace std;
template <class T1,class T2>
void print(map<T1,T2> m) {
map<T1,T2>::iterator p = [Link]();
while(p != [Link]()) { cout<<p->first<<"\t"<<p->second<<"\n";
cout<<endl;
}

p++;

main() {
map<string, string> m;
m["John"]="555-1234";
m["Daniel"]="797-3456";
m["Anna"]="990-8901";
print(m);
[Link](pair<string, string>("Tom", "123-4567"));
map<string, string>::iterator p = [Link]("Tom");
if (p != [Link]()) cout<<p->first<<"\t"<<p->second<<endl;
else cout<<"Key Tom not in map.\n";
p = [Link]("Tomy");
if (p != [Link]()) cout<<p->first<<"\t"<<p->second<<endl;
else cout<<"Key Tomy not in map.\n";
}
C++

Horizon

358

Iterators
Iterators provide a way of specifying a position in a container.
An iterator can be incremented or dereferenced, and two iterators
can be compared.
The simplest iterators in STL allow to traverse the contents of a
collection without having to be concerned about the type of the
collection.
Example:
#include <iostream> #include <vector>
using namespace std;
void main()
{ vector<long> coll;
// Declare the collection
coll.push_back(9); coll.push_back(6);
vector<long>::iterator itr; // Declare the iterator
for (itr=[Link](); itr != [Link](); ++itr)
cout << *itr;
}
C++

Horizon

359

Observations of the previous example :


The increment operator ++ is used to walk the collection.
This increment operator causes the compiler to call the member
function operator++(), which is part of the iterator.
Internally, the iterator may traverse a linked list, iterate a pointer,
or perform more complex processing
Iterators are defined as nested classes.
The declaration vector::iterator refers to a nested type within the
vector class template.
Example:
template<class Type>
class vector{
public: class iterator {
public:
iterator();
};
};
C++

Horizon

360

Every collection class defines its own implementation of iterator.


There is no single implementation of iterator that works across all
classes.
Iterators are the glue that connects algorithms to containers.
Iterators are classified into five categories :
forward
bidirectional
random access
input
output.

C++

Horizon

361

Random access iterator


It can be used to store and retrieve values, provide for
bidirectional traversal, and supports the following operations: ++,
--, +, - and can also be indexed via the [ ] operator.
allow the operations of pointer arithmetic: addition of arbitrary
offsets, subscripting, subtraction of one iterator from another to
find a distance, and so on
A random access iterator is the type used by vector.
Bidirectional iterator
This provides for traversal in both directions and allow multi-pass
algorithms.
It may be incremented to obtain the next element or decremented
to obtain the previous element.
It can store & retrieve values & supports ++ and --, but not + or -.
Bidirectional iterators are used by list.
C++

Horizon

362

Forward iterator
This provides for one-directional traversal of a sequence.
It can store and retrieve values and supports ++.
A Forward Iterator may be
constant i.e. it is possible to access the object it points to
but not to modify it
mutable i.e. it is possible to do both accesssing and
modifying the object.
They permit use of "multi-pass" algorithms.
Input iterator
This can obtain values but not alter them.
It can move in a forward direction only and supports ++.
C++

Horizon

363

Output iterator
This can store values, but not obtain them.
It can move in a forward direction only and supports ++.
Input and Output Iterators permit "single pass" algorithms but do
not necessarily support "multi-pass" algorithms

C++

Horizon

364

Category of iterators provided by each STL container type


vector<T>::iterator and deque<T>::iterator are random access
iterator types
list<T>::iterator is a bidirectional iterator type
All the iterator types of the associative containers are bidirectional

C++

Horizon

365

Algorithms .
.computational procedures
Algorithms are independent from data structures, and are all
parameterised by iterator types.
They can work with user defined data structures, as long as
suitable iterators are provided.
Algorithms are completely independent from the containers Provided that a container supports the required iterators, any
algorithm can be used with it.
Instead of developing algorithms for a specific container, they are
developed for a specific iterator category.
C++

Horizon

366

Classification of Algorithms :
Non-mutating sequence operations
including find, for-each, counting and searching operations.
Algorithms like count and search are examples
Mutating sequence operations
including copying, transformations, removing, generation (a
generator function object creates values that are assigned to
container elements), shuffling and partitioning.
Examples are copy, reverse, or swap
Sorting and related operations
including sorting, searching, merging, set, heap, and
lexicographical comparison operations. Sorting functions include
stable sorting, where the order of equal elements is preserved,
unstable sorting, and partial sorting.
Examples are stable_sort, binary_search, and merge
C++

Horizon

367

Numeric operations
such as partial sums, or applying an operator to all elements in a
sequence.
The STL provides algorithms for: accumulate, inner_product,
partial_sum, and adjacent_difference.
Set Operations
mathematical set operations, such as set_union and
set_intersection. These algorithms only work on sorted
containers.
Heap Operations
Heaps are a very useful and efficient data structure that is often
used to implement priority queues. The STL provides
facilities for making heaps and using them.
Miscellaneous Operations
such as min and next_permutation
C++

Horizon

368

Example :

(complete this program as an excercise)

vector<int> v; //... fill v


// Sort the vector
sort([Link](), [Link]());
// Print each element of a vector of integers
void print (int i) {cout << i;}
for_each([Link](), [Link](), print);
//Copy the vector
vector<int> v2([Link]()) ;
copy([Link](), [Link](), [Link]());
//Transform v2 - square each element
int square(int i) { return i * i; }
transform([Link](),[Link](), [Link](), square};
C++

Horizon

369

Function Objects
A Function Object, or Functor is any object that can be called as if it
is a function.
Function object is an ordinary function, or a function pointer or
(more generally) is an object of a class with operator() defined.
Instead of passing a function pointer to an algorithmic template, the
interface accepts an object with operator() defined.
class Func {
public :
int operator()() {cout<<"func object :: \n" ; return 6666 ;}
void operator()(int t) {cout<<"func object :: "<<t<<"\n" ;}
void operator()(int t, int m) {cout<<"func object :: "<<t<<" :: "<<m<<"\n" ;}
};
void main() {
Func func ;
cout<<func()<<endl ;
func(2) ;
func(7, 8) ;
}
C++

Horizon

370

Function objects and function templates greatly increase the power


and efficiency of the library.
Example : a vector v of doubles could be transformed to the vector w
as -:
transform([Link](), [Link](), [Link](), negate<double>());
transform([Link](), [Link](), [Link](), myfunc<double>()); etc

The STL provides function objects for all of the comparison


operators in the language.
Example :
less can be used to sort a container ascendingly and greater to sort it
descendingly.
STL includes many predefined function objects, eg, arithmetic
operations (plus, minus, multiplies, divides, modulus, & negate),
comparisons (equal_to, not_equal_to greater, less, greater_equal, &
less_equal), and logical operations (logical_and, logical_or, & logical_not).
C++

Horizon

371

A simple example :
class less {
int val;
public:
less (int v) : val (v) {}
int operator () (int v) { return v < val; }
};
main( ) {
less less_than_five (5);
cout << "2 is less than 5: " << (less_than_five (2) ? "yes" : "no");
}

Output: 2 is less than 5: yes

C++

Horizon

372

The basic function object are :


Generator : objects that can be called as f( )
Unary Function :objects that can be called as f(x)
Binary Function : objects that can be called as f(x,y)
This list could obviously be extended to ternary function and
beyond, but, in practice, no STL algorithms require function objects
of more than two arguments.
All other function object concepts defined by the STL are
refinements of these three.
Function objects that return bool are an important special case.
A Unary Function whose return type is bool is called a Predicate
A Binary Function whose return type is bool is called a Binary
Predicate.

C++

Horizon

373

Adaptable Function Objects :


An adaptable function object, however, does specify what the
argument and return types are, and provides nested typedefs so that
those types can be named and used in programs.
If F0 is a model of Adaptable Generator, then it must define
F0::result_type.
If F1 is a model of Adaptable Unary Function it must define
F1::argument_type
F1::result_type
If F2 is a model of Adaptable Binary Function it must define
F2::first_argument_type
F2::second_argument_type
F2::result_type.
The STL provides base classes unary_function and binary_function
to simplify the definition of Adaptable Unary Functions and
Adaptable Binary Functions.
C++

Horizon

374

Some more examples :


Fill a vector with random numbers.
[In this example, the function object is simply a function pointer. ]
vector<int> V(100);

generate([Link](), [Link](), rand);

Sort a vector of double.


[In this example, the function object is an object of a user-defined
class.]
struct less_mag : public binary_function<double, double, bool>
{
bool operator()(double x, double y) { return x < y; }
};
vector<double> V(5) ;
sort([Link](), [Link](), less_mag());

It would be necessary to include the following files : vector,


algorithm, functional
C++

Horizon

375

Adaptors
Adaptors are template classes that provide an existing class with a
new interface.
Adaptors can be used to create new interfaces for containers or
iterators.
Adaptors are casting wrappers that change the appearance of a
container (building a stack from a list), or an iterator (converting a
bidirectional iterator to a reverse iterator).
For example, the copy function expects an input iterator to get its
data from. The istream class has the right functionality: it acts as a
source of data, but it has the wrong interface: it uses << etc.
There is an adaptor called istream_iterator that provides the
interface that copy expects, translating requests into istream
operations.
C++

Horizon

376

Container Adaptors
These can be used to create a specialized container from an
existing, more general container.
The operations of the new container are implemented using the
underlying operations of the existing containers.
Thus new containers can be created without much additional effort,
since most of the functionality is already provided by the existing
container.
The STL provides three container adaptors:
stack<Container>
queue<Container>
deque<Container>
C++

Horizon

377

#include <vector>
#include <stack>

Output :

9
main( )
{
stack <vector<int>, vector<int> >
for (int i=0; i < 10; i++)
[Link] (i) ;
while ( ![Link]() )
{
cout << [Link]() << " ;
[Link]() ;
}
cout << endl ;
}

C++

876543210
st ;

Horizon

378

Iterator Adaptors
These adaptors can be used to extend the functionality of an
existing iterator.
The STL provides three iterator adaptors:
Reverse iterators : Random access iterators and bi-directional
iterators can be traversed forwards and backwards. By applying
the reverse_iterator adaptor to either a random access iterator or
a bi-directional iterator an iterator is obtained that will traverse
the same container in the reverse direction.
Insert iterators : Iterators behave a lot like pointers; if you
assign a new value to a container through it's iterator, you will
overwrite any value that is already at the location specified by
the iterator. Sometimes, it is desirable to be able to insert a new
element at that location in the container.
C++

Horizon

379

Raw storage iterators : Raw storage iterators allow algorithms


to use raw, uninitialized memory during their execution. The
raw_storage_iterator is used by several internal algorithms for
partitioning and merging elements in a container.
STL provides three different insert iterators. Each type of adaptor
performs the insertion into the container in a different place.
back_insert_iterators add elements to end of container. The
algorithm uses the back_insert function to do the insertions, it
can only be used with vectors, lists, and deques.
front_insert_iterators add elements to front of container.
push_front is used for insertions - can only be used on lists,
deques.
insert_iterators add elements to container at location specified
when the iterator is constructed. This iterator can be used to
insert new elements anywhere within a container, not just at the
front or the end. It can be used with any of the STL containers.
C++

Horizon

380

Allocator
Allocators encapsulate information on memory models, allocation
and deallocation primitives, and object sizes.
They are an aid to portability, because all of the containers are
parameterised in terms of allocators.
They also enable custom allocation schemes to be used with the
library.
Allocators separate the STL from the dependencies of the
underlying memory model of the machine architecture.
Each container is given an allocator when it is constructed.
C++

Horizon

381

Whenever a container inserts or removes an element, it uses its


allocator to allocate and deallocate the memory for the object.
The container does not know anything about the memory model of
the machine, it relies on the allocator for all of its memory needs.
The details of the allocator interface are still subject to change.
An allocator must be considered as a "black box". That is, a
container's memory allocation strategy may be selected by
instantiating the container template with a particular allocator, but
no assumptions must be made about how the container actually
uses the allocator.
The default allocator, alloc, is usually the best choice.

C++

Horizon

382

The various allocators are as follows :


alloc

The default allocator. It is thread-safe, and usually has the best


performance characteristics.

A thread-safe allocator that uses a different memory pool for


each thread
Can be used only if the operating system provides pthreads.
Usually faster than alloc, especially on multiprocessor systems.
Can, however, cause resource fragmentation: memory
deallocated in one thread is not available for use by other
threads.
single_client_alloc A fast but thread-unsafe allocator.
Programs having one thread, this allocator might be faster than
alloc.

pthread_alloc

malloc_alloc

C++

An allocator that uses the standard library function malloc.


Is thread-safe but slow
Horizon

383

Examples
vector<double> V(100, 5.0); // Uses the default allocator
// Creates a vector containing 100 elements each
// initialised to 5.0
vector<double, single_client_alloc> local([Link](), [Link]());

Template specifications for some of the containers :


template <class T, class Allocator=allocator <T> > class vector
template <class T, class Allocator=allocator <T> > class deque
template <class T, class Allocator=allocator <T> > class list
template <class Key, class T, class Comp=less<Key>, class Allocator=allocator
<T> > class map

C++

Horizon

384

Exercise 1: Fill two containers with same number of int values. Create a new
container, whose elements are sum of appropriate elements in the original
containers.
#include <vector> #include <algorithm> #include <iostream>
#include <functional>
void main (void) {
vector<int> a; vector<int> b;
for (int i = 0; i < 4; i++) {
a.push_back (i*2);
//0, 2, 4, 6
b.push_back ((i+1)*3); //3, 6, 9, 12
}
vector<int> c(4); // allocate memory for 4 int values!!
// use the algo "transform" and the function object "plus"
// transfrom takes the elements of vectors a and b, adds them using
// plus and writes the results to c
transform ([Link](), [Link](), [Link](), [Link](), plus<int>() );
for(i = 0; i < [Link](); i++)
cout<<c[i]<<"\t";
cout<<endl;
}

C++

Horizon

385

Exercise 2: Write a generator object which can be used with the STL
algorithm generate (group 2) to fill containers with certain values. It should
be possible to specify a starting value and a step size, so that the first
element in the container is the starting value and every further element is the
sum of the preceding element and the step size.
#include <vector> #include <algorithm>
#include <iostream.h>
template <class value_type> class gen {
value_type
start, step;
public:
gen() : start(0), step(1) {}
gen (value_type sta, value_type ste) : start(sta), step(ste) {}
value_type operator() () {
value_type tmp = start; start += step; return tmp;
} };
void main () {
vector<int> v(10);
generate ([Link](), [Link](), gen<vector<int>::value_type> (1, 2) );
for(int i=0; i<[Link](); i++) cout<<v[i]<<"\t" ;
cout<<endl ;
}
C++

Horizon

386

Exercise 3 : Create a vector of integer elements, finds the position of the first
zero element in the vector, and then the position of the next zero element in
the vector.
#include <iostream> #include <vector> #include <algorithm>
void main() {
vector<int> v(10); //0,0,0,0,0,0,0,0,0,0
v.push_back(1);
//0,0,0,0,0,0,0,0,0,0,1
v.push_back(5);
//0,0,0,0,0,0,0,0,0,0,1,5
[Link]([Link](), 1) ;
//1,0,0,0,0,0,0,0,0,0,0,1,5
vector<int>::iterator i1 = [Link]();
vector<int>::iterator i2 = [Link]();
vector<int>::iterator first = find(i1, i2, 0); // find first zero occurrence
if(first == i2) cout << "vector has no zeroes" << endl;
else {
// find the second zero occurrence
vector<int>::iterator second = find(first, i2, 0);
if (second == i2)
cout << "vector has one zero" << endl;
else cout << "vector has two or more zeroes" << endl;
}
}
C++

Horizon

387

Exercises
1) Design a library which provides for the following data structures :
vector, stack, list, map (to store a key value pair). Each of these
classes should be defined as template classes. The basic features to
be provided by these classes should be as follows :
addition and deletion of an item
exceptions to be generated when an action becomes illegal
For each class give a complete design before going into
implementation. For example, for a vector you could identify the
following features :
o It is a dynamically adjustable size array.
o An item can be added or deleted only at the end.
o All items are accessible and modifiable.

C++

Horizon

388

1) Define and implement a network protocol as follows :


The protocol defines a connection oriented service i.e., before
the exchange of any data a connection has to be formally
established which needs to be closed explicitly.
Connection is established between two processes running on the
same system.
Data could be transferred in both directions simultaneously i.e.,
a full duplex system.
Data exchanged could be of a variable size.
The protocol would allow an iterative server handle only one
client at a time.
Connection :
A server is identified by its name which has to be known to the
client.
C++

Horizon

389

The server creates a connection object and writes this object in a


global file. This object contains the name of the server
(ServerId). This file could contain multiple such objects.
A client tries a connect function (could be a member of a
connection class) which would read this global file and try to
establish a connection to the server requested by the client
(identified by the server name).
Connection establishment would mean creating a file (named by
the server name) to which data would be written by the client
and then read by the server and vice versa.
The server in turn is always waiting to open such a file
successfully which comes into existence only when the client
creates it.
Test this protocol by creating an echo server.
C++

Horizon

390

1) Develop template functions for the following global algorithms :


Sort : to sort a vector
template <class T, class Comparator>
void SortAscend (vector<T> &v, Comparator Comp)
Sorting would be done on the basis of the greaterthan function
available in the Comparator.
template <class T, class Comparator>
void SortDescend (vector<T> &v, Comparator Comp)
Sorting would be done on the basis of the lessthan function
available in the Comparator.

C++

Merge : to merge two vectors and the result is a sorted vector


template <class T>
vector<T> & Merge(vector<T> &v1, vector<T> &v2)
Horizon

391

You might also like