Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Annamalai University

Download as pdf or txt
Download as pdf or txt
You are on page 1of 161

IT0213

ANNAMALAI UNIVERSITY
DIRECTORATE OF DISTANCE EDUCATION

MSc INFORMATION TECHNOLOGY


FIRST SEMESTER

OBJECT ORIENTED PROGRAMMING


Annamalai University

Copyright Reserved
(For Private Circulation Only)
Object Oriented Programming
Table Of Contents

Unit-I Page no

1.0 Introduction 1
1.1 Objectives 1
1.2 Content 1
1.2.1 What is Object –Oriented Programming? 1
1.2.2 Encapsulation 2
1.2.3 Polymorphism 2
1.2.4 Inheritance 3
1.2.5 C++ Console I/O 4
1.2.6 C++ Comments 5
1.2.7 Classes: A First Look 6
1.2.8 Some Differences Between C And C++ 9
1.2.9 Introducing function overloading 11
1.2.10 Constructor And Destructor Functions 12
1.2.11 Constructor That Takes Parameters 14
1.2.12 Introduction To Inheritance 15
1.2.13 Object Pointers 18
1.2.14 In-Line Function 19
1.2.15 Automatic In-Lining 20
1.3 Revision Points 21
1.4 Intext Questions 21
1.5 Summary 22
1.6 Terminal Exercises 22
1.7 Supplementary Materials 22
1.8 Assignment 23
1.9 Reference Books 23
1.10 Learning Activities 23
1.11 Keywords 23

Unit-II

2.0 Introduction
2.1 Objectives
Annamalai University 24
24
2.2 Content 24
2.2.1 Assigning Objects 24
2.2.2 Passing Objects To Functions 25
2.2.3 Returning objects from functions: 26
2.2.4 An Introduction To Friend Functions 27
2.2.5 Arrays Of Objects 29
2.2.6 Using Pointers To Objects 30
2.2.7 The This Pointer 31
2.2.8 USING New AND Delete 33
2.2.9 MORE ABOUT new AND delete 35
2.2.10 References 38
2.2.11 Passing References To Objects 40
2.2.12 Returning References 42
2.2.13 Independent References And Restrictions 43
2.3 Revision Points 44
2.4 Intext Questions 45
2.5 Summary 45
2.6 Terminal Exercises 45
2.7 Supplementary Materials 45
2.8 Assignments 46
2.9 Learning Activities 46
2.10 Reference Books 46
2.11 Keywords 46

Unit-III

3.0 Introduction 47
3.1 Objectives 47
3.2 Content 47
3.2.1 Overloading Constructor Functions 47
3.2.2 Creating And Using A Copy Constructor 50
3.2.3 Using Default Arguments 56
3.2.4 Overloading And Ambiguity 59
3.2.5 Finding The Address Of An Overloaded Function 62
3.2.6 The Basics Of Operator Overloading 64
3.2.7 Overloading Binary Operators 65
3.2.8 Overloading The Relational And Logical Operators 69
3.2.9 Overloading A Unary Operator 70
3.2.10 Using Friend Operator Functions 73
3.2.11 A Closer Look At The Assignment Operator 78
3.2.12 Overloading The [] Subscript Operator 80
3.3 Revision Points 84
3.4 Intext Questions 84
3.5 Summary 84
3.6 Terminal Exercises 85

3.8 Assignments
Annamalai University
3.7 Supplementary Materials 85
85
3.9 Reference Books / E-References 85
3.10 Learning Activities 86
3.11 Keywords 86

Unit-IV

4.0 Introduction 87
4.1 Objectives 87
4.2 Content 87
4.2.1 Base Class Access Control 87
4.2.2 Using Protected Members 90
4.2.3 Constructors, Destructors And Inheritance 92
4.2.4 Multiple Inheritance 94
4.2.5 Virtual Base Classes 98
4.2.6 Some C++ I/O Basic 100
4.2.7 Formatted I/O 101
4.2.8 Using Width( ), Precision( ), And Fill( ) 103
4.2.9 Using I/O Manipulators 106
4.2.10 Creating your own inserters 108
4.2.11 Creating Extractors 110
4.3 Revision Points 112
4.4 Intext Questions 113
4.5 Summary 113
4.6 Terminal Exercises 114
4.7 Supplementary Materials 114
4.8 Assignments 114
4.9 Reference Books 114
4.10 Learning Activities 115
4.11 Keywords 115

Unit-V

5.0 Introduction 116


5.1 Objectives 116
5.2 Content 116
5.2.1 Creating Your Own Manipulators 116
5.2.2 File I/O Basics 118
5.2.3 Unformatted, Binary I/O 122
5.2.4 More Unformatted I/O Functions 125
5.2.5 Random Access 127
5.2.6 Checking The I/O Status 130
5.2.7 Customized I/O And Files 132
5.2.8 Pointers To Derived Classes 134
5.2.9 Introduction To Virtual Functions 136
Annamalai University
5.2.10 More About Virtual Functions
5.2.11 Applying Polymorphism
139
139
5.2.12 Templates And Exception Handling 140
5.2.13 Exception Handling 145
5.3 Revision Points 153
5.4 Intext Questions 154
5.5 Summary 154
5.6 Terminal Exercises 154
5.7 Supplementary Materials 155
5.8 Assignments 155
5.9 Reference Books 155
5.10 Learning Activities 155
5.11 Keywords 156

Annamalai University
Object Oriented Programming

UNIT – I

1.0) Introduction
This chapter provides an overview of the key concepts embodied in C++. C++ is
an object-oriented programming language. Its features are highly interrelated. It is a
powerful way to approach the task of programming. C++ also supports all of C’s rich
set of I/O functions. We can use any of them in the C++ program. In C++, the class
forms the basics of the object-oriented programming. Specifically, it is the class that is
used to define the nature of an object.

This chapter also describes about constructors and destructors. Object-oriented


programming provides a support for initializing objects when they are created and
destroy them when they are no longer needed. C++ contain two special member
functions dealing with the internal working of a class. These functions are the
constructors and the destructors. Also c++ allows a programmer to build a hierarchy of
classes. The inheritance principle reduces the amount of writing, as the derived classes
do not have to be written again. Also c++ proposes a new feature called Inline function.

1.1) Objectives

In this chapter you will get to know the key concepts in C++. Classes, console
I/O, constructor and destructor functions, inline functions. The reader will get the basic
idea of programming in C++.

1.2) Content
1.2.1 What is Object –Oriented Programming?

Object-oriented programming is a powerful way to approach the task of


programming. Since its early beginnings, programming has been governed by various
methodologies. At each critical point in the evolution of programming, a new approach
was created to help the programmer handle increasingly complex programs. The first
programs were created by toggling switches on the front panel of the computer.
Annamalai University
Obviously, this approach is suitable for only the smallest programs. Next, assembly
language was invented, which allowed longer programs to be written. The next advance
happened in the 1950s when the first high-level language (FORTRAN) was invented.

By using a high-level language, a programmer was able to write programs that


were several thousand lines long. However, the method of programming used early on
was an ad hoc, anything-goes approach. While this is fine for relatively short programs, it
yields unreadable (an unmanageable)”spaghetti code” when applied to larger programs.
The elimination of ”spaghetti code” became feasible with the invention of structured
programming language in the 1960s. These languages include ALGOL & Pascal. In loose
terms, C is a structured language and most likely the type of programming you have been

Page 1
Object Oriented Programming

doing would be called structured programming. Structured programming relies on well-


defined control structures, code blocks, the absence (or at least minimal use) of the
GOTO, a stand-alone subroutines that support recursion and local variables. The essence
of structured programming, the average programmer can create & maintain programs that
are up to 50000 lines long.

Although structured programming has yielded excellent results when applied to


moderately complex programs, even it fails at some point, after a program reaches a
certain size. To allow more complex programs to be written, a new approach to the job of
programming was needed. Towards this end, object-oriented-programming was invented.
OOP takes the best of the ideas embodied in structured programming and combines them
with powerful new concepts that allow you to organize your programs more effectively.
Object-oriented-programming encourages you to decompose a problem into its
constituent parts. Each component becomes a self-contained object that contains its own
instructions and data that relate to that object. In this way, complexity is reduced and the
programmer can manage larger programs.

All OOP languages, including C++, share three common defining traits:
encapsulation, polymorphism, and inheritance. Let’s look at these concepts now.

1.2.2 Encapsulation

Encapsulation is the mechanism that binds together code and the data it
manipulates, and keeps both safe from outside interference and misuse. In an object-
oriented language, code and data can be combined such a way that a self-contained
“black box“is created. When code and data are linked together in this fashion, an object is
created. In other words, an object is the device that supports encapsulation.

Within an object, code, data, or both may be private to that object or public.
Private code or data is known to and accessible only by another part of the object. That is,
private code or data cannot be accessed by a piece of the program that exists outside the
object. When code or data is public, other parts of your program can access it even
through it is defined within an object. Typically, the public parts of objects are used to
provide a controlled interface to the private of the object.

For all intents and purposes, an object is a variable of a user-defined type. It may
Annamalai University
seem strange that an object that links both code and data can be thought of as a variable.
However, in object-oriented programming, this is precisely the case. Each time you
define a new type of object, you are creating a new data type. Each specific instance of
this data type is a compound variable.

1.2.3 Polymorphism

Polymorphism (from the GREEK, meaning “many forms “) is the quality that
allows one name to be used for two or more related but technically different purposes. As
it relates to OOP, polymorphism allows one name to specify a general class of actions.

Page 2
Object Oriented Programming

Within a general class of actions, the specific action to be applied is determined by the
type of data. For example, in C, which does not significantly support polymorphism, the
absolute value action requires three distinct functions names: abs( ), labs( ), and fabs( ).
These functions compute and return the absolute value of an integer, a long integer, and a
floating-point value, respectively. However, in C++, which supports polymorphism, each
function can be called by the same name, such as absolute. (One way this can be
accomplished is shown later in this chapter) the type of data used to called the function
determines which specifies version of the function is actually executed. As you will see,
in C++, it is possible to use one function name for many different purposes. This is called
function overloading.
More generally, the concept of polymorphism is characterized by the idea of ”one
interface”, multiply methods,” which means using a generic interface for a group of
related activities. The advantage of polymorphism is that it helps to reduce complexity by
allowing one interface to specify a general class of action. It is the complier’s job to
select the specific action as it applies to each situation. You, the programmer, don’t need
to do this selection manually. You need only remember and utilize the general interface.
As the example in the preceding paragraph illustrates, having three names for the
absolute value function instead of just one makes the general activity of obtaining the
absolute value of a number more complex than it actually is.
[
Polymorphism can be applied to operators, too. Virtually all-programming
languages contain a limited application of polymorphism as it relates to the arithmetic
operators. For example,in C,the + sign is used to add integers,long integers,characters and
floating-point values.In this cases,the compiler automatically knows which type of
arithmetic to apply.In C++,you can extend this concept to other type of data that you
define.This type of polymorphism is called operator overloading.

The key point to remember about polymorphism is that it allows you to handle
greater complexity by allowing the creation of standard interfaces to related activities.

1.2.4 Inheritance

Inheritance is the process by which one object can acquire the properties of
another. More specifically, an object can inherit a general set of properties to which it can
add those features that are specific only to it. Inheritance is important because it allows an

Annamalai University
object to support the concept of hierarchical classification. Most information is made
manageable by hierarchical classification. For example, think about a description of the
house. A house is part of the general class called building. In turn, building is part of the
more general class structure, which is part of the even more general class of objects that
we call man-made. In each case, the child class inherits all those qualities associated
with the parent and adds to them its own defining characteristics.Without the use of
ordered classifications,each object would have to define all characteristics that relate to it
explicitly.However,through inheritance,it is possible to describe an object by stating what
general class(or classes) it belongs to along with those specific traits that make it unique.

As you will see,inheritance plays a very important role in OOP.

Page 3
Object Oriented Programming

1.2.5 C++ Console I/O


Since C++ is a superset of C , all elements of the C language are also contained in
the C++ language .This implies that all C programs are also C++ programs by default.
(Actually, there are some very minor exceptions to this rule , which are discussed later).

Therefore , it is possible to write C++ programs that look just like C programs.
While there is nothing wrong with this per se, it dose mean that you will not be take full
advantage of C++ .To get the maximum benefit from C++, you must write C++-style
programs. This means using a coding style and features that are unique to C++.

Perhaps the most common C++-specific features used by C++ programmers are
its approach to console I/O. While you may still use functions such as printf () and
scanf(), C++ provides a new, and better , way to perform these types of I/O operations.
In C++,I/O is performed using I/O operators instead of I/O functions .The output operator
is << and the input operator is >>. As you know, in C, these are the left and right shift
operators, respectively. In C++, they still retained their original meanings (left and right
shift) but they also take on the expanded role of performing input and output. Consider
this C++ statement:

cout <<”This string is output to the screen.\n”;

This statement causes the string to be displayed on the computer’s screen. Cout is
predefined string that is automatically linked to the console when a C++ program begins
execution it is similar to c’s stdout. As in C, C++ console I/O may be redirected but for
the rest of this discussion,it is assumed that the console is being used.
By using the<< output operator, it is possible to output any of C++’s basic types. For
example,this statement outputs the value 100.99:

cout<<100.99;

In general, to output to the console, use this form of the << operator:

cout<<expression;

Here expression can be any valid C++ expression – including another output expression.
To input a value from the keyboard, use the >> input operator.
Annamalai University
For example, this fragment inputs an integer value into num:

int num;
cin >> num;

Notice that num is not preceded by an &. As you know, when you use c’s scanf()
function to input values ,variables must have their addresses passed to the function so
they can receive the values entered by the user. This is not the case when you are using

Page 4
Object Oriented Programming

C++’s input operator (the reason for this will become clear as you learn more about
C++.)
In gendral to input values from the keyboard, use this form of >>:

cin >>variable;

The expanded role of <<and>> are examples of operator overloading.


In order to use the C++I/O operators, you must include the header <iostream.h> in your
program. As explained earlier, this is one of C++’s standard headers and is supplied by
your C++ compiler

EXAMPLE:
This program outputs a string, two integer values ,and a double floating-point value:

#include<iostream.h>
using namespace std;
int main()
{
int i, j;
double d;
i=10;
j=20;
d=99.101;
cout<<”Here are some values:”;
cout<< i;
cout<<’ ‘;
cout<< j;
cout <<’ ‘;
cout<< d;
return 0;
}
The output of this program is shown here.

Here are some values: 10 20 99.101

1.2.6 C++ Comments


Annamalai University
In C++, you can include comments in your program two different ways. First, you
can use the standard, C-like comment mechanism. That is, begin a comment with /* and
end it with */. As with c, this type of comment cannot be nested in C++.

The second way that you can add a remark to your C++ program is to use the
single-line comment. A single-line comment begins with a // and stops at the end of the
line. Other than the physical end of the line (that is, a carriage-return/linefeed
combination), a single-line comment uses no comment terminator symbol.

Page 5
Object Oriented Programming

Typically, C++ programmers use c-like comments for multiline commentaries


and reserve C++-style single-line comments for short remarks.

EXAMPLE:
Here is a program that contains both c and C++-style comments:

/*
this is a c-like comment.

This program determines whether


An integer is odd or even.
*/

#include<iostream.h>
using namespace std;
int main()
{
int num; // this is a C++ single-line comment
// read the number
cout <<”enter number to be tested:”;
cin >> num;
// see if even or odd
if ((num%2)= =0) cout <<”Number is even \n”;
else cout << “number is odd \n”;
return 0;
}

1.2.7 Classes: A First Look


Perhaps the single most important feature of C++ is the class. The class is the
mechanism that is used to create objects.As such, the class is at the heart of many C++
features. Although the subject of classes is covered in great detail throughout this book
classes are so fundamental to C++ programming that a brief overview is necessary here.
A class is declared using the class keyword.the syntax of a class declaration is
similar to that of a structure. Its general form is shown here:

Annamalai University
class class-name{
//private functions and variables
public:
//public functions and variables
}object-list;

In a class declaration, the object-list is optional. As with a structure, you can


declare class objects later,as needed .while the class-name is also technically optional,
from a practical point of view it is virtually always needed. The reason for this is that the
class-name becomes a new type name that is used to declare objects of the class.

Page 6
Object Oriented Programming

Functions and variables declared inside a class declaration are said to be members
of that class.by default, all functions and variables declared inside a class are private to
that class. This means that they are accessible only by other members of that class. To
declare public class a member, the public keyword is used, ollowed by a colon. all
functions and variables declared after the public specifier are accessible both by other
members of the class and by any other part of the program that contains the class.

Here is a simple class declaration:

class myclass{
//private to myclass
int a;
public:
void set_a(int num)
int get_a();
};

This class has one private variable, called a and two public functions, set_a() and
get_a(). Notices that functions are declared within a class using their prototype
forms.functions that are declared to be part of a class are called member functions. Since
a is private, it is not accessible by any code outside myclass. However, since set_a() and
get_a() are members of my class, they can access a. further , get_a() and set_a() are
declared as public members of myclass and can be called by any other part of the
program that contains myclass.

Although the functions get_a() and set_a() are declared by myclass , they are not
yet defined.to define a members function,you must link the type name of the class with
the name of the function. You do this by preceding the fuction name with the class name
followed by two colons.the two colons are called the scope resolution operator. For
example,here is the way the member functions set_a() and get_a() are defined:

void myclass :: set_a(int num)


{
a=num;
} Annamalai University
int myclass:: get_a()
{
return a;
}
notice that both set_a() and get_a() have access to a, which is private to myclass.
Because set_a() and get_a() are members of myclass, they can directly access its private
data.
In general, to define a member function you must use this form:

Page 7
Object Oriented Programming

Ret-type class-name::func-name(parameter-list)
{
//body of function
}

here class-name is the name of the class to which the function belongs the declaration of
myclass did not define any objects of type myclass-it only defines the type of object that
will be created when one is actually declared. To create an object,use the class name as a
type specifier. For example,this line declares two objects of type myclass:
myclass ob1,ob2; // these are objects of type myclass

Remember:
A class declaration is a logical abstraction that defines a new type. It determines
what an object of that type will look like. An object declaration creates a physical entity
of that type. That is, an object occupies memory space, but type definition does not.

Once an object of a class has been created, your program can reference its
members by using the dot(period) operator in much the same way that structure members
are accessed. Assuming the preceding object declaration, the following statement calls
set_a() for objects ob1 and ob2:
Ob1.set_a(10); // sets ob1’s version of a to 10
Ob2.set_a(99); // sets ob2’s version of a to 99

As the comments indicate, these statements set ob1’s copy of a to 10 and ob2’s
copy to 99. each object contains its own copy of all data declared within the class. This
means that ob1’s a is distinct and different from the a linked to ob2.

Remember:
Each object of a class has its own copy of every variable declared within the class.

EXAMPLE:
This program demonstrates myclass described in the text. It sets the value of ob1 and ob2
and then displays a’s value for each object :
Annamalai University
#include<iostream.h>
using namespace std;

class myclass
{
// private to myclass
int a;
public:
void set_a(int num);
int get_a();

Page 8
Object Oriented Programming

};
void myclass::set_a(int num)
{
a=num;
}
int myclass::get_a()
{
return a;
}
int main()
{
myclass ob1,ob2;
ob1.set_a(10);
ob2.set_a(99);
cout<<ob1.get_a()<<”\n”;
cout<<ob2.get_a()<<”\n”;
return 0;
}

1.2.8 Some Differences Between C And C++

Although C++ is a super set of C, here are some small differences between the
two, and few of worth knowing from the start. Before proceeding, let’s take time to
examine them.

First, in C, when a function takes no parameters, its prototype has the word void
inside its function parameter list. For example, in C, if a function called f1() takes no
parameters (and returns a char),its prototype will look like this:

char f1(void);

However, in C++, the void is optional. Therefore in C++, the prototype for f1() is usually
written like this:

char f1();

C++ differs from C the way that an empty parameter list is specified. If the preceding
Annamalai University
prototype had occurred in a C program, it would simply mean that nothing is said about
the parameters to the function. In C++, it means that the function has no parameters. This
is the reason that the preceding examples did not explicitly use void to declare an empty
parameter list. (the use of void to declare an empty parameter list is not illegal; it is just
redundant, since most C++ programmers pursue efficiency with nearly religious zeal, you
will almost never see void used in this way.) remember ,in C++, these two declarations
are equivalent:

char f1();

char f1(void);

Page 9
Object Oriented Programming

Another subtle difference between C and C++ is that in a C++ program, all functions
must be prototyped. Remember, in C, prototypes are recommended but technically
optional. In C++, they required. As the examples from the previous section show, a
member function’s prototype contained in a class also serves as its general prototype, and
no other separate prototype is required.

A difference between C and C++ is that in C++, if a function is declared as returning a


value, it must return a value. That is , if a function has a return type other then void, any
return statement with in that function must contain a value. In C , a non-void function is
not required to actually return a value. If it does not, a garbage value is “returned”.

In C, if you do not explicitly specify the return type of a function an integer return type is
assumed. C++ has dropped the “default – to – int “ rule. Thus you must explicitly declare
the return type of all functions.

One other difference between C and C++ that you will commonly encounter in C++
programs has to do with where local variables can be declared. In C, local variables can
be declared only at the start of a block, prior to any “action” statements. In C++, local
variables can be declared anywhere. One advantage of these approach is that local
variables can declared close to where they are first used, thus helping to prevent
unwanted side effects.

Finally, C++ defines the bool data type, which is used to store Boolean (i.e.,true/false)
values. C++ also defines the keywords true and false, which are the only values that the
value of type bool can have. In C++, the outcome of the relational and logical operator s
is a value of type bool, and all conditional statement must evaluate to bool value.
Although this might at first seem to be big change from C, it is not. In fact , it is virtually
transparent. Here’s why: As you know in C, true is any non zero value and false is zero.
This still holds in C++ because any nonzero value is automatically converted into true
and any zero value is automatically converted into false when used in a Boolean
expression. The reverse also occurs: true is converted to 1 and false is converted to 0
when a bool value used in an integer expression. The addition of bool allows more
thorough type checking and gives you a way to differentiate between Boolean and
integer types. Of course its use is optional: bool is mostly a convenience.

EXAMPLES:
Annamalai University
In a C program , it is common practice to declare a main() as show here if it takes no
command-line arguments

int main(void)

However, in C++ the use of void is redundant and unnecessary.

This short C++ program wil not compile because the function sum() is not prototyped:
//this program will not compile.
#include<iostream.h>
using namespace std;

Page 10
Object Oriented Programming

int main()
{
int a,b,c;
cout<<”Ente two numbers”;
cin>>a>>b;
c=sumof(a,b);
cout<<”Some is :”<<c;
return 0;
}
//this function needs a prototype.
sum(int a, b)
{
return a+b;
}

Here is a short program that illustrates how local variables can be declared anywhere
within a block:
#include<iostream.h>
using namespace std;
int main()
{
int i://local var declared at start of block
cout<<”Enter number:”;
cin>>i;
//compute factorial
int j,fact=1; //vars declared after action statement
for(j=i;j<1;j--)
fact=fact*j;
cout<<”Factorial is <<fact;
return 0;
}

The declaration of j and fact near the point of first use is of little value in this
short example: however, in large functions, the ability to declare variables close to the
point of their first can help clarify your code and prevent unintentional side effects.

1.2.9 Introducing function overloading


Annamalai University
After classes, perhaps the next most important and pervasive C++ feature is function
overloading. Not only does function overloading provide the mechanism by which C++
achieves one type of polymorphism, it also forms the basis by which the C++
programming environment can be dynamically extended. Because of the importance of
overloading, a brief introduction is given here.

In C++, two or more functions can share the same name as long as either the type of their
arguments differs or the number of the arguments differs- or both. When two or more
functions share the same name, they are said to be overloaded. Overloaded functions can

Page 11
Object Oriented Programming

help reduce complexity of a program by allowing related operation to be referred to by


the same name.

It is very easy to overload a function: simply declare and define all required versions. The
compiler will automatically select the correct versions based upon the number and / or
type of the arguments used to call the function.

NOTE:

It is also possible in C++ to overload operators. However, before you can fully
understand operator overloading you will need to know about C++.

1.2.10 Constructor And Destructor Functions

If you have writing programs for every long, you know that it is common for parts
of your program to require initialization.the need for initialization is even more common
when you are working with objects. In fact, when applied to real problems, virtually
every object you create will require some sort of initialization. To address this situation,
C++ allows a constructor function to be included in a class declaration. A class’s
constructor is called each time an object of that class is created. Thus any initialization
that needs to be performed on an object can be done automatically by the constructor
function

A constructor function has the same name as the class of which it is a part and has no
return type.

For example, here is a short class that contains a constructor function:


#include<iostream.h>
using namespace std;
class myclass
{
int a;
public :
myclass( ); // constructor
void show( );
}; Annamalai University
myclass :: myclass( )
{
cout<<”In contructor \n”;
a=10;
}
void myclass :: show( )
{
cout<< a;
}

Page 12
Object Oriented Programming

int main( )
{
myclass ob;
ob.show( );
return 0;
}

In the simple example, the value of a is initialized by the constructor myclass( ). The
constructor is called when the object ob is created. An object is created when that
object’s declaration statement is executed. It is important to understand that in C++, a
variable declaration statement is an “ action statement”. When you are programming in
C, it is easy to think of declaration statements as simply establishing variables. However,
in C++, because an object might have a constructor, a variable declaration statement may,
infact, cause a considerable number of action to occur.

Notice how myclass ( ) is defined. As stated, it has no return type.

According to the C++ formal syntax rules it is illegal for a constructor to have a return
type.

For global objects, an object’s constructor is called once, when the program first begins
execution. For local objects, the constructor is called for each time the declaration
statement is executed.

The complement of a constructor is a destructor. This function is called when an object is


destroyed. When you are working with objects, it is common to have to perform some
actions when an object is destroyed. For example, an object that allocates memory when
it is created will want to free that memory when it is destroyed. The name of a destructor
is the name of its class, preceded by a ~.

For example, the following class contains a destructor function:


#include<iostream.h>
using namespace std;
class myclass
{
int a;

Annamalai University
public:
myclass(); // constructor
~myclass();// destructor
void show();
};

myclass :: myclass()
{
cout << “ In constructor\n”;
a=10;
}

Page 13
Object Oriented Programming

myclass:: ~myclass()
{
cout <<”Destructing…\n”;
}

void myclass :: show ( )


{
cout << a << “\n”;
}

int main( )
{
myclass ob;
ob.show ( );
return 0;
}

1.2.11 Constructor That Takes Parameters

It is possible to pass arguments to a constructor to a function. To allow this, simply add


the appropriate parameters to the constructor function’s declaration and definition.
Then,when you declare an object, specify the arguments. To see how this is
accomplished, let’s begin with the sort example shown here:
#include<iostream.h>
using namespace std;
class myclass
{
int a;
public:
myclass ( int x); //constructor
void show ( ) ;
};
void myclass :: show ( )
{
Annamalai University
cout<<”In constructor \n”;
a=x;
}
int main( )
{
myclass ob(4);
ob.show( );
return 0;
}

Page 14
Object Oriented Programming

Here the constructor for myclass takes one parameter. The value passed to
myclass( ) is used to initialize a. Pay special attention to how ob is declared in main( )
the value 4, specified in parentheses following ob, is the argument that is passed to
myclass( )’s parameter x, which is used to initialize a.

Actually, the syntax passing an argument to a parameterized constructor is


shorthand for this longer form:

myclass ob = myclass(4);

However, most C++ programmers use the short form. Actually, there is a slight
technical difference between the two forms that relates to copy constructors, which are
discussed later in this book. But you don’t need to worry about this distinction now.

1.2.12 Introduction To Inheritance

Although inheritance is discussed more fully earlier, it needs to be introduced at


this time. As it applies to C++ , inheritance is the mechanism by which one class can
inherit the properties of another. Inheritance allows a hierarchy of classes to be built,
moving from the most general to the most specific.

To begin, it is necessary to define two terms commonly used when discussing


inheritance. When one class in inherited by another, then the class that is inherited is
called the base class. The inheriting class is called the derived class. In general, the
process of inheritance begins with the definitions of a base class. The base class defines
all qualities that will be common to any derived classes. In essence, the base class
represents the most general descriptions of a set of traits. A derived class inherits those
general traits and adds properties that are specific to that class.

To understand how one class can inherit another, let’s first begin with an example
that, although simple, illustrates many key features of inheritance.

To start, here is the declaration for the base class:


//Define base class.
class B
{
int i;
Annamalai University
public :
void set_i (int n);
int get_i( );
};

//Using this base class, here is a derived class that inherits it:

//Define derived class


class D : public B
{
int j;

Page 15
Object Oriented Programming

public :
void set_j(int n);
int mul( );
};

Look closely at this declaration. Notice that after the class name D there is a colon
followed by the keyword public and the class name B. This tells the complier that class
D will inherit all components of class B. The keyword public tells the complier that B
will be inherited such that all public elements of the base class will also be the public
elements of the derived class. However, all private elements of the base class remind
private to it and are not directly accessible by the derived class.

Here is an entire program that uses the B and D classes:


// A simple example of inheritance.
#include<iostream.h>
using namespace std;
// Define base class.
class B
{
int i;
public:
void set_i(int n);
int get_i( );
};
//Define derived class.
class d : public b {
int j;
public:
void set_j(int n);

};
Annamalai University
int mul( );

// set value i in base.


void b :: seti(int n)
{
i = n;
}
// Return value of i in base.

Page 16
Object Oriented Programming

int b :: get_i( )
{
return i;
}
//set value of j in derived.
void d :: set_j( int n)
{
j = n;
}
//Return value of base’s i times derived’s j.
int d :: mul( )
{
//Derived class can call base class public member functions
return j * get_i( );
}
int main( )
{
d ob;
ob.set_i(10); //load i in base
ob.set_j(4); //load j in derived
cout<<ob.mul( ); //displays 40
return 0;
}

Look at the definition of mul( ). Notice that it calls get_i( ), which is member of
the base class B, not of D, without linking it to any specific object. This is possible
because the public members of B become public members of D. However, the reason that
mul( )must be called get_i( ) instead of accessing i directly is that the private members
Annamalai University
of a base class(in this case,i ) remain private to it and not accessible by any derived class.
The reason that private members of a class are not accessible to derived classes is to
maintain encapsulation. If the private members of a class could be made public simply by
inheriting the class, encapsulation could be easily circumvented.

The general form used to inherit the base class is shown here:

class derived-class-name : access-specifier base-class-name{}

Page 17
Object Oriented Programming

Here access-specifier is one of the following three keywords : public, private, or


protected. For now, just use public when inheriting a class. A complete description of
the access specifiers will be given later in this book.

1.2.13 Object Pointers

So far, you have been accessing members of an object by using the dot operators.
This is the correct method when you are working with an object. However, it is also
possible to access a member of an object via a pointer to that object. When a pointer is
used, the arrow operators(->) rather than the dot operator is employed. (This is exactly
the same way the arrow operator is used when given a pointer to a structure.)

You declare an object pointer just like you declare a pointer to any other type of
variable. Specify its class name, and then precede the variable name with an asterisk. To
obtain the address of an object, precede the object with the & operator, just as you do
when taking the address of any other type of variable.

Just like pointers to other types, an object pointer, when incremented, will point to
the next object of its type.

EXAMPLE
1. Here is a simple example that uses an object pointer:
#include<iostrem>
using namespace std;
class myclass
{
int a;
public :
myclass (int x); //constructor
int get( );
};
myclass : : myclass(int x)
{
a=x;
}
int myclass :: get( )
{ Annamalai University
return a;
}
int main( )
{
myclass ob(120); //create object
myclass * p; //create pointer to object
p=&ob; //put address of ob into p
cout<<”value using object:” <<ob.get( );
cout<<”\n”;
cout<<”value using pointer:” <<p->get( );

Page 18
Object Oriented Programming

return 0;
}

Notice how the declaration


myclass *p;

creates a pointer to an object of myclass. It is important to understand that creation of an


object pointer does not create an object-it creates just a pointer to one. The address of ob
is put into p by using this statement:

p=&ob;

Finally, the program show how the members of an object can be accessed through a
pointer.

We will come back to the subject of object pointers later. Once you know more about
C++. There are several special features that relate to them.

1.2.14 In-Line Function

Before we continue this examination of classes, a short but related digression is


needed. In C++, it is possible to define functions that are not actually called but, rather,
are expanded in line,at the point of each cell. This is much the same way that a C-like
parameterized macro works. We advantage of in-line functions is that they have know
overhand associated with the function call and return mechanism. This means that in-line
functions can be executed much faster than normal functions. (Remember, the machine
instructions that generate the function call and return take time each time a function is
called. If there are parameters, even more time overhead is generated ).

The disadvantage of in-line functions is that if they are too long and called too
often, your program grows longer. For this reason, in general only short functions are
declared as in-line functions.

To declare an in-line function, simply precede the function’s definition with the
inline specifier. For example, the short program show how to declare an in-line function:

Annamalai University
//Example of an in-line function
#include<iostream.h>
using namespace std;
inline int even( int x)
{
return !(x%2);
}

int main( )
{
if(even(10)) cout<<”10 is even\n”;

Page 19
Object Oriented Programming

if(even(11)) cout<<”11 is even\n”;


return 0;
}

In this example, the function even( ), which returns true if its argument is even, is
declared as being in-line. This means that the line

if(even(10)) cout<<”10 is even\n”;

is functionally equivalent to

if(!(10%2)) cout<<”10 is even\n”;

This examples also points out another important feature of using inline: an in-line
function must be defined before it is first called. If it isn’t, the complier has no way to
know that it is supposed to be expanded in-line. This is way even( ) was defined main( ).

The advantage of using inline rather than parameterized macros is twofold.First,


it provides a more structured way to expand short function in line. For example, when
you are creating a parameterized macro, it is easy to forget extra parentheses are often
needed to ensure proper in-line expansion in every case.Using in-line function prevents
such problems.

Second, an in-line function might be able to be optimized more thoroughly by the


complier than a micro expansion. In any event, C++ programmers virtually never use
parameterized macros, instead relying on inline to avoid the overhead of a function call
associated with the short function.

It is important to understand that the inline specifier is a request, not a command,


to the complier. If, for various reasons, the complier is unable to fulfill the request, the
functions complied as a normal function and the inline request is ignored.

Depending upon your complier, several restrictions to in-line function may apply.
For example, some compliers will in-line functions if it contains a static variable, a loop
statement, a switch or a goto, or if the function is recursive. You check your complier’s
is a manual for specific restrictions to in-line functions that might affect you.

Annamalai University
1.2.15 Automatic In-Lining

If a member function’s definition is enough, the definition can be included inside the
class declaration. Doing so causes the function to automatically become an in-line function, if
possible. When a function is defined within a class declaration, the inline keyword is no longer
necessary. (However, it is not an error to use it in this situation). For example, the divisible( )
function from the preceding section automatically in-lined as shown here:
#include<iostream.h>
using namespace std;
class samp
{

Page 20
Object Oriented Programming

int i,j;
public:
samp( int a,int b);
/*divisible( ) is defined here automatically in-lined*/
int divisible( ) { return !(i%j); }
};
samp :: samp (int a, int b)
{
i = a;
j = b;
}

int main( )
{
samp ob1(10,2),ob2(10,3);
//this is true
if(ob1.divisibe( )) cout<<”10 divisible by 2\n”;
//this is false
if(ob2.divisibe( )) cout<<”10 divisible by 3\n”;
return 0;
}

1.3) Revision Points

 OBJECTED-ORIENTED PROGRAMMING- Object-oriented programming


is a powerful way to approach the task of program.
 CONSOLE I/O:- To output to the console, use << operator, To input to the
console, use >>operator
 CLASSES-The class is the mechanism that is used to create objects.
 CONSTRUCTOR - A constructor is a special member function whose main
operation is to initialize the objects of its class.
 DESTRUCTORS - The destructor is called when the function in which the
objects are defined is about to terminate.
 Annamalai University
FUNCTION OVERLOADING - Function overloading means we can use the
same function name to create functions that performs a variety of different
argument tasks.
 INHERITANCE - It is the process of creating new classes from an existing
base class.

1.4) Intext Questions

1) What is Object-oriented programming?


2) Describe briefly the features of I/O system supported by C++?

Page 21
Object Oriented Programming

3) What is a clad in C++?


4) Define function overloading?
5) What is the use of constructor and destructor functions?
6) Define Inheritance?
7) What are inline functions?
8) How can we call a parameterized constructor?
9) What is a header file?

1.5) Summary

 Object-oriented programming is a new way of approaching the job of programming.


 ‘cin’ represents the input stream and ‘cout’ represents the output stream.
 A class declaration defines a new type that links code and data.
 A class can have both variables and functions as members.
 An object declaration creates a physical entity of that type. That is, an object
occupies memory space, but type definition does not.
 Each object of a class has its own copy of every declared within the class.
 By default, function and data declared within a class are private to that class and
may be access only by other members of a class.
 The body of a class contains declaration of variables and functions, collectively
called members.
 The constructors play an important role in initializing an object’s data members and
allocating required recourses such as memory.
 When a function is declared inline the compiler replaces the function call with the
respective function code. A small size function is called inline.

1.6) Terminal Exercises

1) Classes are created using_________ keyword.


2) Constructors have the same name as that of_________.
3) When a function takes no parameters, its prototype has the word__________.
4) To declare an inline function, precede the function’s definition with the ________
specifier.
5) List out any 2 differences between C and C++.
Annamalai University
6) ___________ is the process by which one object can acquire the properties of
another.
7) Give the syntax for creating a class.

1.7) Supplementary Materials

1. Teach yourself C++ , Third edition, Herbert Schildt, Tata McGraw Hill.
2. Programming in C++ - E.Balagurusamy

Page 22
Object Oriented Programming

1.8) Assignment

Define a class to represent a bank account. Include the following members.


Name of the depositor
Account number
Type of account
Balance amount in the account.

Member functions:
To assign initial value
To deposit an account
To withdraw an amount after checking the balance
To display name and balance.

Write a main program to test the program.

1.9) Reference Books

1) Object-oriented Programming In Turbo C++ - Robert Lafore, Galgotia.


2) C++ Programming for the Absolute Beginner (For the Absolute Beginner) by
Dirk Henkemans and Mark Lee
3) http://www.intap.net/~drw/cpp/
4) http://www.glenmccl.com/tutor.htm
5) http://www.research.att.com/~bs/dne.html

1.10) Learning Activities

The following task can be performed by group of students.


Explain the concept of class and give suitable examples.
Explain the concept of inheritance.

1.11) Keywords

Class – A group of objects that share common properties.


Inline
coid
Annamalai University
– A function replaced by statements that define the function.
– A data type in C++.
constructor– A special member function automatically creates an instance of a class.
destructor – A function that is called to de-allocate memory of a class.

Page 23
Object Oriented Programming

UNIT-II

2.0) Introduction

In C++ when one object is created, it can be assigned to another provided that
both objects are of the same type. Also objects can be passed to functions as arguments in
just the same way that other types are passed.

Functions can also return objects. C++ introduces new type of function namely,
FRIEND FUNCTION. They are introduced to handle some specific tasks related to class
objects. It is a nonmember function. A friend function can be called by reference. A
pointer to the address of the object is passed and the called function directly works on the
actual object used in the call.

Objects are variables and have the same capabilities and attributes as any other
type of variable. ’THIS’ keyword is to represent an object that invokes a member
function. Also c++ introduces two new keywords called ‘new’ and ‘delete’. You can
allocate memory and release it respectively. C++ contains a feature that is related to the
pointer, the reference. It is an implicit pointer. It can be passed to a function also can be
returned by it. Although not commonly used, the independent reference is another type of
reference in c++.

2.1) Objectives

In this chapter, it describes about objects, passing objects to functions arrays of


objects, the keywords ‘new’, ‘delete’, ‘reference’, in detail.

2.2) Content
2.2.1 Assigning Objects

One object can be assigned to another provided that both objects are of the same
type. By default, when one data members is made. For example,when an object called o1
Annamalai University
is assigned to another object called o2, the contents of all of o1’s data are copied into the
equivalent members of o2.

This is illustrated by the following problems:


// An example of object assignment:
#include<iostream.h>
using namespace std;
class myclass
{
int a,b;
public :

Page 24
Object Oriented Programming

void set(int i, int j) { a=i; b=j; }


void show ( ) { cout<<a<<’ ‘<<b<<”\n”; }
};
int main( )
{
myclass o1,o2;
o1.set(10,4);
//assign o1 to o2
o2 = o1;
o1.show( );
o2.show( );
return 0;
}

Here, object o1 has its member variables a and b set to the value 10 and 4, respectively.
Next, o1 is assigned to o2. This causes the current value of o1.a to be assigned to o2.a
and o1.b to be assigned to o2.b. Thus, when run, this program displays

10 4

10 4

Keep in mind that an assignment between two objects simply makes the data in those
objects identical. The two objects are still completely separate. For example, after the
assignment, calling o1.set( ) to set the value of o1.a has no affect on o2 or it’s a
value.

2.2.2 Passing Objects To Functions

Objects can be passed to functions as arguments in just the same way that other
types are passed. Simply declare the function’s parameter as a class type and then use
and object of that class as an argument when calling the function. As with other types
of data, by default all objects are passed by value to a function.

EXAMPLE: Here is a sort example that passes an object to a function:


#include<iostream.h>
using namespace std;
class samp
{
Annamalai University
int i;
public :
samp (int n) { i=n; }
int get_i ( ){ return i; }
};
// Return square of o.i.
int sqr_it(samp o)
{

Page 25
Object Oriented Programming

return o.get_i() * o.get_i ( );


}
int main( )
{
samp a(10) , b(2);
cout<<sqr_it(a)<<”\n”;
cout<<sqr_it(b)<<”\n”;
return 0;
}

This program creates a class called samp that contains one integer variable called i .

The function sqr_it() takes an argument of type samp and return the square of that
object’s i value. The output from this program is 100 followed by 4.

2.2.3 Returning objects from functions:

Just as you can pass objects to functions, functions can return objects. To do so,
first declare the function as returning a class type. Second, return a object of that type
using the normal return statement.

There is one important point to understand about returning objects from functions,
however: When an object is returned by a function, a temporary object is automatically
created which holds the return value. It is this is actually returned by the function. After
the value has been returned, this object is destroyed. The destruction of this temporary
object might cause unexpected side effect in some situation, as is illustrated in Example 2
below.

EXAMPLE 2:

Here is an example of a function that returns an object.

// returning a object
#include<iostream.h>
#include<cstring.h>

Annamalai University
using names space std;
class samp
{
char s[80];
public:
void show()
{
cout <<s<<”\n”;
}
void set(char *str) {strcpy(s,str); }
};

Page 26
Object Oriented Programming

// return an object of type samp


samp input()
{
char s[80];
samp str;
cout<<”Enter the string”;
cin>>s;
str.set(s);
return str;
}
int main()
{
samp ob;
//assign returned object to ob
ob = input();
ob.show();
return 0;
}

in this example, input() creates a local object called str and then reads a string from the
keyboard . this string copied into str.s,and then str is returned by the function. This object
is then assigned to ob inside main() when it is returned by the call to input().

2.2.4 An Introduction To Friend Functions

There will be times when you want a function to have access to the private
members of a class without that function actually being a member of that class. Towards
this end , C++ supports friend function. A friend is not a member of a class but still has
access to its private elements.

Two reasons that friend function are useful have to do with operator overloading
and the creation of certain types of I/O functions. You will have to wait until later to see
these uses of a friend in action. However , a third reason for friend function is that there
will times when you want one function to have access to the private members of two or
more different classes. It is this use that is examined here.

Annamalai University
A friend function is defined as a regular, non-member function. However, inside
the class declaration for which it will be a friend, its prototype is also included, prefaced
by the keyword friend. To understand how this works, examine this short program:

//An example of a friend function.


#include<iostream.h>
using names space std;
class myclass
{
int n,d;
public:

Page 27
Object Oriented Programming

myclass(int i,intj){n=i;d=j;}

// declare a friend of myclass


friend int isfactor(myclass ob);
};
/* here is friend function definition. It returns true if d is a factor of n. notice that
the keyword friend is not used in the definition of isfactor() */
int isfactor( myclass ob)
{
if (!(ob.n%ob.d))
return 1;
else
return 0;
}

int main()
{
myclass ob1(10,2),ob(13,3);
if (isfactor (ob1))
cout<<”2 is a factor of 10\n”;
else
cout<<” 2 is not a factor of 10\n”;
if (isfactor(ob2))
cout<< “3 is a factor of 13\n”;
else
cout<<”3 is not a factor of 13\n”;

In this example, myclass declares its constructor function and the friend is factor()
inside its class declaration . Because isfactor() is friend of myclass, isfactor() has access
to its private members. this is why , within its factor(), it is possible to directly refer to
ob.n and ob.d.

It is important to understand that a friend function is not a member of the class for
which it is a friend. thus, it is not possible to call a friend function by using an object
name and a class member access operator (a dot or an arrow).for example ,given the
preceding example, this statement is wrong:

Annamalai University
ob1.isfactor(); // wrong; isfactor() is not a member function, instead, friends are called
just like regular functions.

Although a friend function has knowledge of the private elements of the class for
which it is a friend, it can only access them through an object of the class. That is, unlike
a member function of myclass, which can refer to n or d directly, a friend can access
these variables only in conjunction with an object that is declared within or passed to the
friend function.

Page 28
Object Oriented Programming

Note:

The preceding paragraph brings up an important side issue. when a member


function refers to a private element, it does so directly because a member function is
executed only in conjunction with an object of that class. Thus, when a member function
refers to a private element, the complier knows which object that private element belongs
to by the object that is linked to the function when that member function is called.
However, a friend function is not linked to any object. It simply is granted access to the
private elements of a class. Thus, inside the friend function, it is meaningless to refer to a
private member without reference to a specific object.

Because friends are not members of a class, they will typically be passed one or
more objects of the class for which they are friends. T his is the case with isfactor( ).It is
passed an object of myclass( ), called ob .However, because isfactor( ) is a friend of
nyclass, it can access ob’s private elements. It isfactor( ) had not been made a friend of
myclass, it would not be able to access ob.d or ob.n since n and d are private members of
myclass.

Remember:

A friend function is not a member and cannot be qualified by an object name. It


must be called just like a normal function. A friend function is not inherited. That is,
when a base class includes a friend function, that friend function is not a friend of a
derived class.

One other important point about friend functions is that a friend function can be friends
with more than one class.

2.2.5 Arrays Of Objects

As has been stated several times, objects are variables and have the same
capabilities and attributes as any other type of variable. Therefore, it is perfectly
acceptable for objects to be arrayed. The syntax for declaring an array of objects is
exactly like that used to declare an array of any other type of variable. Further, arrays of
Annamalai University
objects are accessed just like arrays of other types of variables.

Examples:

Here is an example of an array of objects:


#include<iostream.h>
using namespace std;
class samp
{
int a;
public:

Page 29
Object Oriented Programming

void set_a(int n) { a= n;}


int get_a( ) { return a;}
};
int main( )
{
samp ob[4];
int i;
for(i=0; i<4; i++)
ob[i].set_a(i);
for(i=0; i<4; i++)
cout<<ob[i].get_a( );
cout<<”\n”;
return 0;
}
This program creates a four-element array of objects of type samp and then loads
each element’s a with a value between 0 and 3.notice how member functions are called
relative to each array element. The array name, in this case ob , is indexed; then the
member access operator is applied ,followed by the name of the member function to be
called.

2.2.6 Using Pointers To Objects

As discussed earlier, Objects can be accessed via pointers. as you know ,when a
pointer to an object is used the object’s members are referenced using the arrow (-
>)operator instead of the dot(.) operator.
Pointer arithmetic using an object pointer is the same as it is for any other data
type:it is performed relative to the type of the object. For example when an object pointer
is incremented, it points to the previous object.

Example:

Here is an example of object pointer arithmetic:


//pointers to objects.
#include<iostream.h>
using namespace std;
class samp
{
int a, b;
Annamalai University
public:
samp (int n, int m) {a = n;b = m;}
int get_a( ) {return a;}
int get_b( ) {return b;}
};
int main(_
{
samp ob[4]={

Page 30
Object Oriented Programming

samp(1, 2),
samp(3, 4),
samp(5, 6),
samp(7, 8)
};
int i;
samp *p;
p=ob;// get starting address of array
for(i=0;i<4;i++)
{
cout<<p->get_a()<<’ ‘;
cout<<p->get_b()<<”\n”;
p++; // advance to next object
}
cout<<”\n”;
return 0;
}
this program displays
12
34
56
78
As evidenced by the output, each time p is incremented, it points to the next object in the
array.

2.2.7 The This Pointer

C++ contains a special pointer that is called this. This is a pointer that is
automatically passed to any member function when it is called, and it is a pointer to the
object the generates the call. for example given this statement,
Ob.f1( ); // assume that ob is an object

The function f1( ) is automatically passed a pointer to ob-which is the object that
invokes the call. this pointer is referred to as this. It is important to understand that only
member functions are passed a this pointer. For example, a friend does not have a this
pointer.

Example:
Annamalai University
1. As you have seen, when a member function refers to another member of a
class, it does so directly, without qualifying the member with either a class or an object
specifications. For example, examine this short program, which creates a simple
inventory class:

// Demonstrate the this pointer.


# include<iostream.h>
# include<cstring.h>

Page 31
Object Oriented Programming

using namespace std;


class inventory
{
char item[20];
double cost;
int on_hand;
public:
inventory (char *i , double c, int o)
{
strcpy(item, i);
cost = c;
on_hand = o;
}
void show( );
};
void inventory :: show( )
{
cout << item;
cout<<”:$” <<cost;
cout<<”on hand : “on_hand <<”\n”;
}
int main( )
{ inventory ob(“wrench”,4.95,4);
ob.show( );
return 0;
}

As you can see, within the constructor inventory( ) and the member function show ( ), the
member variables item, cost and on_hand are referred to directly. This is because a
member function can be called only in conjunction with an object.

Therefore, the complier knows which object’s data is being referred to. However,
there is an even more subtle explanation. when a member function is called, it is
automatically passed a this pointer to the object that invoked the call. Thus, the preceding
program could be rewritten as shown here:

Annamalai University
//Demonstrate the pointer.
#include<iostream.h>
#include<cstring.h>
using namespace std;
class inventory {
char item[20];
double cost;
int on_hand;
public:
inventory (char *i , double c, int o)
{

Page 32
Object Oriented Programming

strcpy(this->item, i);//access members


this->cost = c; //through the this
this->on_hand =o;//pointer
}
void show( );
};
void inventory: :show( )
{
cout<<this->item;// use this to access members
cout<<”:$”<<this->cost;
cout<<”on hand :”<<this->on_hand<<”\n”;
}
int main()
{
inventory ob (“wrench”, 4.95, 4);
ob.show( );
return 0;
}
Here the member variables are accessed explicitly through the this pointer. Thus , within
show( ).these statements are equivalent:
cost = 1234.23;
this->cost = 123.23;

In fact, the first form is, loosely speaking, a shorthand for the second. While no
c++ programmer would use the this pointer access a class member as just shown, because
the shorthand form is much easier, it is important to understand what the shorthand
implies.

The this pointer has several uses, including aiding in overloading operators. This
use will be detailed in chapter 6.For now, the important thing to understand is that by
default, all member functions are automatically passed a pointer to the invoking object.

2.2.8 USING New AND Delete

Up to now,when memory needed to allocated,you have been using malloc(),and


you have been freeing allocated memory by using free().These are,of course,the standard
Annamalai University
C dynamic allocation functions.While these functions are available in C++,C++ provides
a safer and more convenient way to allocate and free memory.In C++,you can allocate
memory using new and release it using delete. These operators take these general forms:

p-var=new type;
delete p-var;
Here type is the type specifier of the object for which you want to allocate
memory and p-var is a pointer to that type.new is an operator that returns a pointer to
dynamically allocated memory that is large enough to hold an object of type type.delete
releases that memory when it is no longer needed.delete can be called only with a pointer

Page 33
Object Oriented Programming

previously allocated with new.If you call delete with an invalid pointer,the allocation
system will be destroyed,possibly crashing your program.

If there is insuffient available memory to fill an allocation request,one of two


actions will occurs.Either new will return a null pointer or it will generate an exception.
(Exceptions and exception handling are described later in this book;loosely, an exception
is a run-time error that can be managed in a structured fashion.)In Standard C++,the
default behavior of new is to generate an exception when it cannot satisfy an allocation
request.If this exception is not handled by your program,your program will be terminated.
The trouble is that the precise action that new takes on failure has been changed several
times over the past few years.Thus,it is possible that your compiler will not implement
new as defined by Standard C++.

When C++ was first invented,new returned null on failure.Later this was changed
such that new caused an exception on failure.Finally it was decided that a new failure
will generate an exception by default,but that a null pointer could be returned instead, as
an option.Thus,new has been implemented differently at different times by compiler
manufacturers.For example,at the time of this writing,Microsoft’s Visual C++ returns a
null pointer by new fails.Borland C++ generates an exceptions.Although all compilers
will eventually implemented new in compliance with Standard C++,currently the only
way to know the precise action of new on failure is to check your compiler’s
documentation.

Since there are two possible ways that new can indicate allocation failure,and
since different compilers might do so differently,the code in this book will be written in
such a way that both contingencies are accommodated.All code in this book will test the
pointer returned by new for null.This handles compilers that implement new by returning
null on failure,while causing no harm for those compilers for which new throws an
exception.If your compiler generates an exception when new fails,the program will
simply be terminated.Later,when exception handling is described,new will be re-
examined and you will learn how to better handle an allocation failure.You will also learn
about an alternative form of new that always returns a null pointer when an error occurs.

Although new and delete perform functions similar to malloc() and free(),they
have several advantages.First,new automatically allocates enough memory to hold an
object of the specified type.You do not need to use sizeof, for example,to compute the
Annamalai University
number of bytes required.This reduces the possibility for error.Second,new automatically
returns a pointer of the specified type.You do not need to use an explicit type cast the
way you did when you allocated memory by using malloc()(see the following notes) .
Third , both new and delete can be overloaded,enabling you to easily implement your
own custom allocation system.Fourth,it is possible to initializea dynamically allocated
object.Finally,you no longer need to include<cstdlib> with your programs.

Note:
In C, no type cast is require when you assigning the return value of malloc() to a
pointer because the void* returned by malloc() is automatically converted into a pointer

Page 34
Object Oriented Programming

compatible with the type of pointer on the left side of the assignment.However,this is not
the case in C++,which requires an explict type cast when you use malloc().The reason for
this difference is that it allows C++ to enforce more rigorous type checking.

Now that new and delete have been introduced,they will be used instead of
malloc() and free().

2.2.9 MORE ABOUT new AND delete

This section discussed to addition features of new and delete.First,dynamically


allocated objects can be given initial values.Second,dynamically allocated arrays can be
created.
You can give a dynamically allocated object an initial value by using this form of
the new statement:
p-var=new type(initial-value);

To dynamically allocate a one-dimensional array,use this form of new.


p-var=new type[size];

After this statement has executed,p-var will point to the start of an array of size
elements of the type specified.For various technical reasons it is not possible to initialize
an array that is dynamically allocated.

To delete a dynamically allocated array,use this form of delete:


delete[ ] p-var;
This syntax causes the compiler to call the destructor function for each element in
the array.It does not cause p-var to be freed multiple times.p-var is still freed only once.

Notes:
For older compilers,you might need to specify the size of the array that you are
deleting between the square brackets of the delete statement.This was required by the
original definition of C++.However,the size specification is not needed by modern
compilers.

Examples:

Annamalai University
1. The following program allocates memory for an integer and initializes that memory:

//An example of initializing a dynamic variable.


#include<iostream.h>
using namespace std;

int main()
{
int *p;

Page 35
Object Oriented Programming

p=new int(9); //Give initial value of 9

if(!p)
{
cout<<”Allocation Error/n”;
return 1;
}
cout<<”Here is integer at p:”<<*p<<”\n”;
delete p; //Release memory
return 0;
}

As you should expect,this program displays the value 9,which is the initial value
given to the memory pointer to by p.

2. The following program passes initial values to a dynamically allocated object:

//Allocation dynamic objects.


#include<iostream.h>
using namespace std;

class samp
{
int i,j;
public:
samp(init a, int b) {i=a;j=b;}
int get_product() { return i*j;}
};

int main()
{
samp *p;
p=new samp(6,5); //Allocate object with initialization
if(!p)
{
cout<<”Allocation error\n”;

}
Annamalai University
return 1;

cout<<”Product is :”<<p->get_product()<<”\n”;
delete p;
return 0;
}

When the samp object is allocated,its constructor is automatically called and is passed
the values 6 and 5.

Page 36
Object Oriented Programming

3. The following program allocates an array of integers:


// a simple example of new and delete.
#include<iostream.h>
using namespace std;
int main( )
{
int *p;
p=new int[5]; //allocate room for 5 integers
//always make sure that allocation is succeeded
if (!p) {
cout<<”Allocation error \n“;
return 1;
}
int i;
for(i=0;i<5;i++) p[i]=i;
for(i=0;i<5;i++)
{
cout<<”Here is integer at p[“<<i<<”]:”;
cout<<p[i]<<”\n”;
}
delete[ ] p; //release memory
return 0;
}
This program displays the following:
Here is integer at p[0] : 0
Here is integer at p[1] : 1
Here is integer at p[2] : 2
Here is integer at p[3] : 3
Here is integer at p[4] : 4

4. The following program creates a dynamic array of objects:

//Allocating dynamic objects.


#include<iostream.h>
using namespace std;
class samp
{
Annamalai University
int i,j;
public :
void set_ij(int a, int b) { i=a; j=b; }
int get_product( ) { return i*j; }
};
int main( )
{
samp *p;

Page 37
Object Oriented Programming

int i;
p=new samp[10]; //allocate object array
if(!p)
{
cout<<”Allocation error\n”;
return 1;
}
for(i=0;i<10;i++)
p[i].set_ij(i,i);
for(i=0;i<10;i++) {
cout<<”Product[“<<i<<”]is:”;
cout<<p[i].get_product( )<<”\n”; }
delete[] p;
return 0;
}

This program displays the following :


Product[0] is : 0
Product[1] is : 1
Product[2] is : 4
Product[3] is : 9
Product[4] is : 16
Product[5] is : 25
Product[6] is : 36
Product[7] is : 49
Product[8] is : 64
Product[9] is : 81

2.2.10 References

C++ contains a feature that is related to the pointer: the reference. A reference
is an implicit pointer that for all intents and purposes acts like another name for a
variable. There are three ways that a reference can be used. First, a reference can be
passed to a function. Second, a reference can be returned by a function. Finally, an
independent reference can be created. Each of this applications of the reference is
examined, beginning with reference parameters.
Annamalai University
Without a doubt, the most important use of reference is as a parameter to a
function. To help you understand what a reference parameter is and how it works, let’s
first start with a program that uses a pointer(not a reference) as a parameter:

#include<iostream.h>
using namespace std;
void f(int *n); //use a pointer parameter
int main( )
{

Page 38
Object Oriented Programming

int i=0;
f(&i);
cout << “here is i’s new value:”<<i<<’\n’;
return 0;
}
void f(int *n)
{
*n=100; //put 100 into the argument pointed to by n
}

Here f( ) loads the value 100 into the integer pointed to be n. In this program, f(
) is called with the address of i in main( ). Thus, after f( ) returns, i contains the value
100.

This program demonstrates how a pointer is used as a parameter to manually


create a call-by-reference parameter-passing mechanism. In a C program, this is the only
way to achieve call-by-reference.

However, in C++, you can completely automate this process by using a reference
parameter. To see how, let’s rework the previous program. Here is a version that uses a
reference parameter:

#include<iostream.h>
using namespace std;
void f(int &n); //declare a reference parameter
int main( )
{
int i=0;
f(i);
cout<<”Here is i’s new value : “<<i<<’\n’;
return 0;
}
// f( ) now uses a reference parameter
void f(int &n)
{
// notice that no * is needed in the following statement

}
Annamalai University
n = 100; //put 100 into the argument used to call f( )

Examine this program carefully. First, to declare a reference variable or


parameter, you precede the variable’s name with the & This is how n is declared as
a parameter to f( ). Now that n is a reference, it is no longer necessary-or even legal –
to apply the * operators. Instead, each time n is used within f( ), it is automatically
treated as a pointer to the argument used to call f( ).

Page 39
Object Oriented Programming

This means that the statement n=100; actually puts the value 100 into the variable
used to call f( ), which, in this case, is i. Further, when f( ) is called, there is no need
to precede the argument with the &. Instead, because f( ) is declare as taking a
reference parameter, the address to the argument is automatically passed to f( ).

To review, when you use a reference parameter, the complier automatically


passes the address of the variable used as the argument. There is no need to manually
generate the address of the argument by preceding it with an & (in fact, it is not
allowed). Further, within the function, the complier automatically uses the variable
pointed to by the reference parameter. There is no need to employee the *(and again,
it is not allowed). Thus, a reference parameter fully automates the call-by-reference
parameter-passing mechanism.
It is important to understand that you cannot change what a reference is pointing to.

For example, if the statement


n++;

were put inside f( ) in the preceding program, n would still be pointing to i in main(
). Instead of incrementing n, this statement increament the value of the variable being
referenced (in this case, i).

Reference parameters offer several advantages over their (more or less )


equivalent pointer alternatives. First, from a practical pointer of view, you no longer
need to remember to pass the address of an argument. When a reference is used, the
address is automatically passed. Second, in the opinion of many programmers,
reference parameters offer a cleaner, more elegant interface than the rather clumsy
explicit pointer mechanism. Third, as you will see in the next section, when an object
is passes to a function as a reference, no copy is made. This is one way to eliminate
the troubles associated with the copy of an arguments damaging something needed
elsewhere in the program when its destructor function is called.

2.2.11 Passing References To Objects

As you have learnt earlier, when an object is passed to a function by use of the
default call-by-value parameter-passing mechanism, a copy of that object is made.
Although the parameter’s constructor function is not called, its destructor function is
Annamalai University
called when the function returns. As you should recall, this can cause serious problem in
some instance -when the destructor frees dynamic memory, for example.

One solution to this problem is to pass an object by reference. (The other solution
involves use of copy constructors, which are discussed in Chapter 5.) When you pass the
object by reference, no copy is made, and therefore its destructor function is not called
when the function return. Remember, however, that changes made to the object inside the
function affect the object used as the argument.

Page 40
Object Oriented Programming

Note:
It is critical to understand that a reference is not a pointer. Therefore, when an
objects passes by reference, the member access operator remains the dot [.], not the arrow
[->]
EXAMPLE:

1. The following is an example that demonstrates the usefulness of passing an object by


reference. First, here is a version of a program that passes an object of myclass by value to a
function called f( ):

#include<iostream.h>
using namespace std;
class myclass
{
int who;
public :
myclass(int n)
{
who = n;
cout<<”Contructing”<<who<<”\n”;
}

~ myclass( ) { cout<<”destructing”<<who<<”\n”; }
int id( ) { return who; }
};

//o is passed by value.


void f(myclass 0)
{
cout<<”Received”<<o.id( )<<”\n”;
}
int main( )
{
myclass x(1);
f(x);
return 0;
} Annamalai University
This function displays the following
Constructing 1
Received 1
Destructing 1
Destructing 1

Page 41
Object Oriented Programming

As you can see, the destructor function is called twice-first when the copy of
object 1 is destroyed when f( ) terminates and again when the f( ) terminates and again
when the program finishes.

However, if the program is changed so that f( ) uses a reference parameter, no


copy is made and, therefore, no destructor is called when f( ) returns:

#include<iostream.h>
using namespace std;
class myclass
{
int who;
public :
myclass(int n) {
who = n;
cout<<”Contructing”<<who<<”\n”;
}
~ myclass( ) { cout<<”Destructing”<<who<<”\n”; }
int id( ) { return who; }
//Now o is passed by referance.
void f(myclass &o)
{
// note that . operator is still used!!!
cout<<”Received”<<o.id( )<<”\n”;
}
};
int main( )
{
myclass x(1);
f(x);
return 0;
}
This version displays the following output:
Constructing 1
Received 1
Destructing 1

REMEMBER
Annamalai University
When accessing members of an object by using a reference, use the dot operator, not the
arrow.

2.2.12 Returning References

A function can return a reference. As you will see in Chapter 6, returning a


reference can be very useful when you are overloading certain types of operators.
However, it also can be employed to allow a function to be used on the left side of an
assignment statement. The effect of this is both powerful and startling.

Page 42
Object Oriented Programming

EXAMPLE
1. To begin, here is a very simple program that contains a function that returns a
reference:
// A simple example of a function returning a reference.
#include<iostream.h>
using namespace std;
int &f( ); // return a reference
int x;
int main( )
{
f ( ) = 100; // assign 100 to reference returned by f( )
cout<<x<<”\n”;
return 0;
}
// Return an int reference.

int &f( )
{
return x; // return a reference to x.
}
Here function f( ) is declared as returning a reference to an integer. Inside the
body of the function, the statement return x; does not return the value of global variable
x, but rather, it automatically returns x’s address(in the form of a reference). Thus, inside
main( ), the statement f( ) = 100; puts the value 100 into x because f( ) has returned a
reference to it.

To review, function f( )returns a reference. Thus, when f( ) is used on the left


side of the assignment statement, it is this reference, returned by f( ), that is being
assigned to. Since f( ) returns a reference to x(in this example), it is x that receives the
value 100.

2.2.13 Independent References And Restrictions

Although not commonly used, the independent reference is another type of


Annamalai University
reference that is available in C++. An independent reference is a reference variable that is
variable that in all effects is simply another name for another variable. Because
references cannot be assigned new values, an independent reference must be initialized
when it is declared.

NOTE:
Because independent references are sometimes used, it is important that you know
about them. However, most programmers feel that there is no need for them and that they
can add confusion to a program. Further, independent references exist in C++ largely

Page 43
Object Oriented Programming

because there was no compelling reason to disallow them. But for the most part, their use
should be avoided.

There are number of restrictions that applied to all types of references. You
cannot reference another reference. You cannot obtain the address of a reference. You
cannot create arrays of reference, and you cannot reference a bit-field. Reference must be
initialized unless they are members of a class, are return values, or are function
parameters.

Remember : References are similar to pointers, but they are pointers.

EXAMPLE

Here is a program that contains an independent reference:


#include<iostream.h>
using namespace std;
int main( )
{
int x;
int &ref=x; //create an independent reference
x = 10; //this two statements
ref=10; //are functionally equivalent

ref=100;
//this prints the number 100 twice
cout<<x<<’ ‘<<ref<<”\n”;
return 0;
}

In the above program, the independent reference ref serves as a different name for x.
From the practical point of view, x and ref are equivalent.

2.3) Revision Points

 Annamalai University
One object can be assigned to another provided the both objects are of the same
type.
 The member selector operator-->allows a particular member of object to be
referenced.
 An array of pointers to objects is often used to handle a group of objects.
 When a member function is called, it is automatically passed an implicit argument
that is a pointer to the objects that generated the call. This is called ‘this’ pointer.

Page 44
Object Oriented Programming

2.4) Intext Questions


1. How does an object be passed to function as an argument?
2. What is a friend function?
3. What is the use of this pointer?
4. Define new and delete
5. How can pointer represent objects?
6. What are references? Give an example
7. How an object is returned by a function?
8. What is an independent reference? Give its restrictions
9. How can we pass reference to objects?
10. Give an example for a friend function
11. How to use object to manipulate an array of objects?

2.5) Summary

 A reference is essentially an implicit pointer that acts as another name for an


object.
 To create a call-by-reference you must explicitly pass the address of an argument
to the function.
 When you pass by reference, no copy of the object is made.
 You cannot reference another reference also create a pointer to a reference.
 When passing parameters by reference,remember that changes to the object inside
the function affect the calling object.
 The new operator is used to create dynamic objects and delete operator is used to
release the memory allocated to the dynamic object by new operator.
 A function that has access to the private members of a class but is not itself a
member of a class.

2.6) Terminal Exercises


1. ___________ function that although not a member of a class is able to access
the private members of that class.

Annamalai University
2. A data type that holds the address of a location in memory is ___________.
3. ___________ is a pointer to current object.
4. The keywords which allocate memory space is _________ and which destroys
the allocated space is __________.
5. A ___________ is an implicit pointer that for all intents and purposes acts like
another name for a variable.
6. A ___________ is a reference variable that is all effects is simply another name
for another variable.

2.7) Supplementary Materials


1. Teach yourself c++, Herbert schidlt, Tata mcgraw hill

Page 45
Object Oriented Programming

2. The C++ Programming Language (Special 3rd Edition) by Bjarne


Stroustrup (Hardcover - Feb 15, 2000)

2.8) Assignments
1. Write an assignment for friend function.
2. Write an assignment on references with perfect example.

2.9) Learning Activities


The following tasks can be performed,
- Explain in detail the ‘friend function’.
- Explain the ‘reference’ in c++ with examples.
- Difference between ‘new’ and ‘delete’ operators.

2.10) Reference Books


3. Object oriented programming in turbo c++ - Robert Lafore , Galgotia
4. http://www.cplusplus.com/doc/tutorial/
5. http://www.desy.de/gna/html/cc/Tutorial/tutorial.html

2.11) Keywords
‘new’ - It is used to create dynamic objects.

‘delete’ - It releases the memory allocated to the dynamic object by the new operator.

‘friend’ - A function not a member of a class is able to access the private members
of that class.

‘this’ - This is a pointer to the current object.

‘reference’ – An implicit pointer for all intents and purposes acts like another name
for a variable.

Annamalai University
Independent reference – It is a reference variable that is variable that in all effects is
another name for another variable.

Page 46
Object Oriented Programming

UNIT – III

3.0) Introduction
This chapter gives an overview about the interesting features of C++. One such
feature is Overloading; it allows a function or operator to be given more than one
definition. Another important feature of C++ is a new class object from an existing
object.

As stated earlier, Overloading refers to the use of the same thing for different
purposes. This means that we can use the same functions name to create function that
performs a variety of different arguments tasks.

Besides from performing the special role of initializing, constructor functions are no
different from other overloading constructor functions.

3.1) Objectives

This chapter teaches the concept of overloaded function and overloaded operators.
At the end of the chapter the reader will be able to write polymorphic functions.

3.2) Content

3.2.1 Overloading Constructor Functions

It is possible-indeed, common-to overload a class’s constructor function. (It is not


possible to overload a destructor, however.) There are three main reason why you will
want to overload a constructor function: to gain flexibility, to support arrays, and to
create copy constructors. The first two of these are discussed in this section. Copy
constructors are discussed in the next section.

One thing to keep in mind as you study the examples is that there must be a
constructor function for each way that an object of a class will be created. If a program
attempts to create an object for which no matching constructor is found, a compile-time
error occurs. This is way overloaded constructor functions are so common to C++
programs. Annamalai University
EXAMPLES
Perhaps the most frequent use of overloaded constructor functions is to provide
option of either giving an object an initialization or not given it one.

For example, in the following program, o1 is given an initial value, but o2 is not.
If you remove the constructor that has the empty argument list, the program will not
compile because there is no constructor that matches a noninitialized object of type
samp. The reverse is also true: If you remove the parameterized constructor, the program

Page 47
Object Oriented Programming

will not compile because there is no match for an initialized object. Both are needed for
this program to compile correctly.

#include<iostream.h>
using namespace std;
class myclass( )
int x;
public :
// overload constructor two ways
myclass( ) { x = 0; } // no initializer
myclass(int n) { x = n; } //initializer
int getx( ) { return x; }
};
int main ( )
{
myclass o1(10); //declare with initial value
myclass o2; //declare without initializer
cout<<”o1:”<<o1.getx( )<<’\n’;
cout<<”o2:”<<o2.getx( )<<’\n’;
return 0;
}

2. Another common reason constructor functions are overloaded is to allowed both


individual objects and arrays of objects to other within a program. As you probably
know from your own programming experience, it is fairly common to initialize a single
variable, but it is not as common to initialize an array.(Quite often array values are
assigned using information known only when the program is executing.) Thus, to allow
noninitialized arrays of objects along with initialized objects, you must include a
constructor that supports initialization and one that does not.

For instance, assuming the class myclass for Example 1, both of these declarations are
valid:
myclass ob(10);
myclass ob[5];

By providing both the parameterized and a parameterless constructor, your


Annamalai University
program allows the creation of objects that are either initialized or not as needed.

Of course, once you have defined both parameterized and parameterless


constructors you can use them create initialized and noninitialized arrays. For example,
the following program declares two arrays of type myclass; one is initialized and the
other is not:

#include<iostream.h>
using namespace std;
class myclass

Page 48
Object Oriented Programming

{
int x;
public :
// overload constructor two ways
myclass( ) { x = 0; } //no initializer
myclass( int n ) { x = n; } //initializer
int getx( ) { return x; }
};
int main( )
{
myclass o1[10]; //declare array without initializers
//declare with initializers
myclass o2[10]={1,2,3,4,5,6,7,8,9,10};
int i;
for(i=0;i<10;i++)
{
cout<<”o1[“<<i<<”]:”<<o1[i].getx( );
cout<<’\n’;
cout<<”o2[“<<i<<”]:”<<o2[i].getx( );
cout<<’\n’;
}
return 0;
}
In this example, all elements of o1 are set to 0 by the constructor function. The elements
of o2 are initialized as shown in the program.

3. Another reason overloading constructor functions is to allow the programmer to select


the most convenient method of initializing an object. To see how, first examine the next
example, which creates a class that holds a calendar date. It overloads the date( )
constructor two ways. One form accepts the date as a character string. In the other form,
the date is passed as three integers.

#include<iostream.h>
#include<cstdio.h> //Included for sscanf()
using namespace std;

class date
{
Annamalai University
int day,month,year;
public:
date(char *str);
date(int n,int d,int y)
{
day=d;
month=m;
year=y;
}

Page 49
Object Oriented Programming

void show()
{
cout<<month<<’/’<<day<<’/’;
cout<<year<<’\n’;
}
};

date::date(char *str)
{
sscanf(str,”%d%*c%d%*c%d”,&month,&day,&year);
}

int main()
{ //Construct date object using string
date sdate(“12/31/99”);

//Construct date object using integers


date idate(12,31,99);

sdate.show();
idate.show();
return 0;
}

The advantage of overloading the date() constructor,as shown in this program,is


that you are free to use whichever version most conveniently fits the situation in which it
is being used.For example,if a date object is being created from user input,the string
version is the easiest to use.However,if the date object is being constructed through some
sort of internal computation,the three-integer parameter version probably makes more
sense.

Although it is possible to overload a constructor as many times as you want,doing


so excessively has a destructuring effect on the class.From a stylistic point of view,it is
best to overload a constructor to accommodate only those situation that are likely to occur
Annamalai University
frequently.For example,overloading date() a third time so the date can be entered in
terms of milliseconds makes little sense.However,overloading it to accept an object of
type time_t(a type that stores a system date and time)could be very valuable.(See the
Mastery Skills Check exercises at the end of this chapter for an example that does just
this.)

3.2.2 Creating And Using A Copy Constructor


One of the more important forms of an overloaded constructor is the copy
constructor.As numerous examples from the preceding units have shown, problems can

Page 50
Object Oriented Programming

occur when an object is passed to or retuned from a function.As you will learn in this
section,one way to avid these problems is to define a copy constructor.

To begin, let’s restate the problem that a copy constructor is designed to


solve.When an object is passed to a function, a bitwise(i.e.,exact) copy of that object is
made and given to the function parameter that receives the object.However, there are
cases in which this identical copy is not desirable.For example,if the object contains a
pointer to allocate memory, the copy will point to the same memory as does the original
object.Therefore, if the copy makes a change to the contents of this memory,it will be
changed for the original object too! Also, when the function terminates,the copy will be
destroyed, causing its destructor to be called.This might lead to undesired side effects that
further affects the original objects.

A similar situation occurs when an object is returned by a function.The compiler


will commonly generate a temporary object that holds a copy of the value returned by the
function.(This is done automatically and is beyond your control.)This temporary object
goes out of a scope once the value is returned to calling routine, causing the temporary
object’s destructor to be called.However, if the destructor destroys something needed by
the calling routine(For example, if it frees dynamically allocated memory),trouble will
follow.
At the core of these problems is the fact that a bitwise copy of the object is being
made.To prevent these problems, you, the programmer, need to define precisely what
occurs when a copy of an object is made so that you can avoid undesired side effects.The
way you accomplish this is by creating a copy constructor.By defining a copy
constructor, you can fully specify exactly what occurs when a copy of an object is made.

It is important for you to understand that C++ defines two distinct type of
situation in which the value of one object is given to another.The first situation is
assignment.The second situation is initialization, which can occur three ways:

*When an object is used to initialize another in a declaration statement,


*When an object is passed as a parameter to a function, and
*When a temporary object is created for use as a return value by a function.

The copy constructor only applies to initializations.It does not applied to


assignments.
Annamalai University
By default, when an initialization occurs, the compiler will automatically provide
a bitwise copy.(That is, C++ automatically provides a default copy constructor that
simply duplicates the object.) However, it is possible to specify precisely how one object
will initialize another by defining a copy constructor.Once defined, the copy constructor
is called whenever an object is used to initialize another.

Remember:Copy constructors do not affect assignment operations.

Page 51
Object Oriented Programming

The most common form of copy constructor is shown here:

Classname(const classname &obj) {


// body of constructor
}
Here obj is a reference to an object that is being used to initialize another
object.For example,assuming a class called myclass,and that y is an object of type
myclass,the following statement would invoke the myclass copy constructor:

myclass x = y; //y explicitly initializing x


func1(y); //y passed as a parameter
y = func2( ); //y receiving a returned object

In the first two cases, a reference to y would be passed to the copy constructor.
In the third, a reference to the object returned by func2( ) is passed to copy constructor.

Examples:

1. Here is an example that illustrates why an explicit copy constructor function is


needed. This program creates a very limited “safe” integer array type that prevents array
boundaries from being overrun. Storage for each array is allocated using new, and a
pointer to the memory is maintained within each array object.

/*This program creates a “safe” array class. Since space for the array is dynamically
allocated, a copy constructor is provided to allocate memory when one array object is
used to initialize another. */
#include<iostream.h>
#include<cstdlib.h>
using namespace std;

class array
{
int *p;
int size;
public: Annamalai University
array(int sz) { //Constructor
p=new int[sz];
if(!p) exit(1);
size=sz;
cout<<”Using ‘normal’ constructor\n”;
}
~array( ) {delete[] p;}

//Copy constructor

Page 52
Object Oriented Programming

array(const array &a);

void put(int i, int j) {


if(i>=0 && i<size) p[i] = j;
}
int get(int i) {
return p[i];
}
};

/*Copy constructor.
In the following memory is allocated specifically for the copy, and the address of this
memory is assigned to p. Therefore, p is not pointing to the same dynamically allocated
memory as the original object. */

array::array(const array &a)


{
int i;

size = a.size;
p=new int[a.size]; //allocated memory for copy
if(!p) exit(1);
for(i=0;i<a.size;i++) p[i] = a.p[i]; // Copy contents
cout<<”Using copy constructor\n”;
}

int main( )
{
array num(10); //this calls “normal” constructor
int I;
// put some values into the array
for(i=0;i<10;i++) num.put(i,i);
// display num
for(i=9;i>=0;i--) cout<<num.get(i);
cout<<”\n”;

Annamalai University
// create another array and initialize with num
array x = num; // this invoked copy constructor
// display x
for(i=0;i<10;i++) cout<<x.get(i);

return 0;
}

When num is used to initialize x, the copy constructor is called, memory for the
new array is allocated and stored in x. p, and the contents of num are copied to x’s array.

Page 53
Object Oriented Programming

In this way , x and num have arrays that have the same values , but each array is separate
and distinct. (that is , num.p and x.p do not point to the same piece of memory.) If the
copy constructor had not been created, the bitwise initialization array x =num would have
resulted in x and num sharing the same memory for their arrays! (that is , num.p and x.p
would have, indeed , pointed to the same location .)
The copy constructor is called only for initializations. For example, the following
sequence does not call the copy constructor defined in the preceding program:
Array a(10);
Array b(10);

B = a; //does not call copy constructor.


In this case, b=a performs the assignment operation.

2. To see how the copy constructor helps prevent some of the problems associated
with passing certain types of objects to functions, consider this (incorrect) programs:

// this program has an error.


#include<iostream.h>
#include<cstring.h>
#include<cstdlib.h>
using namespace std;
class strtype {
char *p;
public:
strtype(char *s);
~strtype() { delete [] p; }
char *get() {return p;}
};
strtype::strtype(char *s)
{
int l;
l=strlen(s)+1;
p=new char[l];
if(!p) {
cout<<”Allocation error\n”;
exit(l);
}
strcpy(p,s);
Annamalai University
}
void show(strtype x)
{
char *s;
s=x.get();
cout<<s<<”\n”;
}

Page 54
Object Oriented Programming

int main()
{
strtype a(“Hello”),b(“There”);
show(a);
show(b);
return 0;
}

in this program , when a strtype object is passed to show() , a bit wise copy is made
(since no copy constructor has been defined) and put into parameter x. thus when the
function returns , x goes out of scope and is destroyed. This , of course, causes x’s
destructor to be called, which frees x.p. however , the memory being freed is the same
memory that is still being used by the object used to call the function. This results in an
error.

The solution to the preceding problem is to define a copy constructor for the
strtype class that allocates memory for the copy when the copy is created. This approach
is used by the following, corrected, program:

/* this program uses a copy constructor to allow strtype objects to be passed to


function.*/
#include<iostream.h>
#include<cstring.h>
#include<cstdlib.h>
using namespace std;
class strtype {
char *p;
public:
strtype(char *s); //constructor
strtype(const strtype &o); // copy constructor
~strtype() { delete [] p;}//destructor
char *get() { return p; }
};
// “Normal “ constructor
Annamalai University
strtype ::strtype(char *s)
{
int l;
l=strlen(s)+1;
p=new char[l];
if(!p) {
cout<<”Allocation error\n”;
exit(l);
}
strcpy(p,s);

Page 55
Object Oriented Programming

// copy constructor
strtype::strtype(const strtype &o)
{
int l;
l=strlen(o.p)+1;
p=new char[l];//allocate memory for new copy
if(!p) {
cout<<”Allocation error \n”;
exit(l);
}
strcpy(p,o.p); //copy string into copy
}
void show(strtype x)
{
char *s;
s=x.get();
cout<<s<<”\n”;
}
int main()
{
strtype a(“Hello”),b(“There”);
show(a);
show(b);
return 0;
}

Now when show() terminates and x goes out of scope , the memory pointed to by
x.p(which will be freed) is not the same as the memory still in use by the object passed to
the function.

3.2.3 Using Default Arguments


There is a feature of C++ that is related to function overloading. This feature is
called the default argument, and it allows you to give a parameter a default value when
Annamalai University
no corresponding argument is specified when the function is called. as you will see ,
using default argument is essentially a short hand form of function overloading.

To give a parameter a default argument, simply follow that parameter with an


equal sign and the value you want it to default to if no corresponding argument is present
when the function is called. For example, this function gives its two parameters default
values of 0:
void f(int a=0,int b=0);

Page 56
Object Oriented Programming

Notice that this syntax is similar to variable initialization. This function can now
be called three different ways. First, it can be called with both arguments specified.
second, it can be called with only the first argument specified. In this case, b will default
to 0. Finally, f() can be called with no arguments, causing both a and b to default to 0.
that is the following invocations of f() are all valid:

F(); //a and b default to 0


F(10); //a is 10, b defaults to 0
F(10,99) // a is 10, b is 99

In this example, it should be clear that there is no way to default a and specify b.
When you create a function that has one or more default argument, those arguments must
be specified only once: either in the function’s prototype or in its definition if the
definition precedes the function’s first use. The default cannot be specified in both the
prototype and the definition. This rule applies even if you simply duplicate the same
defaults.

As you can probably guess, all default parameters must be to the right of any
parameters that do not have defaults. Further, once you begin to define default parameters
, you cannot specify any parameters that have no defaults.

One other point about default arguments: they must be constants or global
variables. They cannot be local variables or other parameters.

Examples:
Here is a program that illustrates the example described in the preceding discussions:

//a simple first example of default arguments


#include<iostream.h>
using namespace std;
void f(int a =0,int b=0)
{
cout<<”a:”<<a<<”,b:”<<b;
cout<<”\n”;
}
int main()
{
f();
Annamalai University
f(10);
f(10,99);
return (0);
}
as you should expect, this program displays the following output:
a:0,b:0
a:10,b:0
a:10,b:99

Page 57
Object Oriented Programming

Remember that once the first default argument is specified , all following
parameter must have defaults as well. for example, this slightly different version of
f()causes a compile-time error:
void f(int a=0,int b)\\wrong!b must have the default, too
{
cout<<”a:”<<a<<”,b:”<<b;
cout<<”\n”;
}

to understand how default arguments are related to function overloading , first


consider the next program , which overload the function call rect_area(). This function
returns the area of the rectangle.

// compute area of a rectangle using overload function.


#include<iostream.h>
using namespace std;
//Return area of a non – square rectangle.
Double rect_area(double length, double width)
{
return length * width;
}
// Return area of a square .
double rect_area(double length)
{
return length*length;
}
int main()
{
cout<<”10 x 5.8 rectangle has area:”;
cout<<rect_area(10.0,5.8)<<”\n”;
cout<<”10 x 10 square has area:”;
cout<<rect_area(10.0)<<”\n”;
return 0;
}
In this program , rect_area() is overloaded two ways. In the first way, both
Annamalai University
dimensions of a rectangle are passed to the function. This version is used when the
rectangle is not a square. However, when the rectangle is square, only one argument need
be specified, and the second version of rect_area() is called.

If you think about it , it is clear that in this situation there is really no need to have
two different functions. Instead, the second parameter can be defaulted to some value that
acts as a flag to rect_area(). When this value is seen by the function, it uses the length
parameter twice. Here is an example of this approach:

Page 58
Object Oriented Programming

// Compute area of a rectangle using default arguments.


#include<iostream.h>
using namespace std;
//return area of a rectangle.
Double rect_area(double length,double width=0)
{
if(!width) width=length;
return length * width;
}
int main()
{
cout<<”10 x 5.8 rectangle has area:”;
cout<<rect_area(10.0,5.8)<<”\n”;
cout<<”10 x 10 square has area:”;
cout<<rect_area(10.0)<<”\n”;
return 0;
}

Here 0 is the default value of width . This value was chosen because no rectangle
will have a width of 0. (Actually, a rectangle with a width of 0 is a line.) Thus, if this
default value is seen, rect_area() automatically uses the value in length for the value of
width.
As this example shows, default arguments often provide a simple alternative to
function overloading. (Of course, there are many situations in which function overloading
is still required.)

3.2.4 Overloading And Ambiguity


When you are overloading functions, it is possible to introduce ambiguity into
your program. Overloading-caused ambiguity can be introduced through type
conversions, reference parameters, and default arguments. Further, some type of
ambiguity is caused by the overloaded functions themselves. Other types occur in the
manner in which an overloaded function is called. Ambiguity must be removed before
your program will compile without error.

Examples: Annamalai University


1.One of the most common types of ambiguity is caused by C++’s automatic
type conversions rules. As you know, when a function is called with an argument that is
of a compatible (but not the same) type as the parameter to which it is being passed, the
type of the argument is automatically converted to the target type. In fact, it is this sort of
type conversion that allow a function such as putchar() to be called with a character even
though its argument is specified as an int. however , in some cases , this automatic type
conversion will cause an ambiguous situation when a function is overloaded. To see how,
examine this program:

Page 59
Object Oriented Programming

// this program contains an ambiguity error


#include<iostream.h>
using namespace std;
float f(float I )
{
return I /2.0;
}
double f(double I)
{
return I / 3.0;
}
int main()
{
float x=10.09;
double y=10.09;
cout<<f(x);//unambiguous – use f(float)
cout<<f(y); //unambiguous –use f(double)
cout<<f(10); //ambiguous , convert 10 to double or float??
Return 0;
}

as the comments in main() indicate , the compiler is able to select the correct
version of f() when it is called with either a float or a double variable. However, what
happens when it is called with an integer? Does the compiler call f (float) or f (double)?
(Both are valid conversions!) In either case, it is valid to promote an integer into either a
float or a double. Thus, the ambiguous situation is created.

This example also point out that ambiguity can be introduced by the way an
overloaded function is called. The fact is that there is no inherent ambiguity in the
overloaded versions of f() as long as each is called with an unambiguous argument.
Here is another example of function overloading that is not ambiguous in and of itself.
However, when this function is called with the wrong type of argument, C++’s automatic
conversion rules cause an ambiguous situation.

// This program is ambiguous .


Annamalai University
#include<iostream.h>
using namespace std;
void f(unsigned char c)
{
cout << c;
}
void f(char c)
{
cout << c;
}

Page 60
Object Oriented Programming

int main()
{
f(‘c’);
f(86); // which f() is called???
return 0;
}

Here when f () is called with the numeric constant 86, the compiler cannot know
whether to call f(unsigned char) or f(char). Either conversion is equally valid, thus
leading to ambiguity.

One type of ambiguity is caused when you try to overload function in which the
only difference is the fact that one uses a reference parameter and the other uses the
default call-by-value parameter. Given C++’s formal syntax, there is no way for the
compiler to know which function to call. Remember, there is no syntactical difference
between calling a function that takes a value parameter and calling a function that takes a
reference parameter. For example:

// An ambiguous program.
#include<iostream.h>
using namespace std;
int f(int a, int b)
{
return a+b;
}
// this is inherently ambiguous
int f(int a, int &b)
{
return a-b;
}
int main()
{
int x=1, y=2;
cout << f(x,y);//which version of f() is called????
Return 0;
} Annamalai University
Here, f(x,y) is ambiguous because it could be calling either version of the
function. In fact, the compiler will flag an error before this statement ism even specified
because the overloading of the two functions is inherently ambiguous and no reference to
them could be resolved.
Another type of ambiguity is caused when you are overloading a function is
which one or more overloaded functions use a default argument. Consider this program:

//Ambiguity based on default arguments plus overloading,


#include<iostream.h>

Page 61
Object Oriented Programming

using namespace std;

int f(int a)
{
return a*a;
}
int f(int a, int b = 0)
{
return a*b;
}
int main()
{
cout << f(10, 2); // calls f(int, int)
cout << f(10); // ambiguous – cal f(int) or f(int, int)???

return 0;
}
Here the call f(10,2) is perfectly acceptable and unambiguous. However, the
compiler has no way of kn0wing whether the call f(10) us calling the first version if f() or
the second version with b defaulting.

3.2.5 Finding The Address Of An Overloaded Function


To conclude this chapter, you will learn how to find the address of an overloaded
function. Just as in C, you can assign the address f a function (that is, its entry point) to a
pointer and access that function via that pointer. A function’s address is obtained by
putting its name on the right side of an assignment statement without any parentheses or
arguments. For example, if zap() is a function, assuming proper declarations, this is a
valid way to assign p the address of zap();

P = zap;

In C, any type of pointer can be used to point to a function because there is only
one function that it can point to. However, in C++ the situation is a bit more complex
because a function can be overloaded. Thus, there must be some mechanism that
determines which function’s address is obtained.
The solution is both elegant and effective. When obtaining the address of an
Annamalai University
overloaded function, it is the way the pointer is declared that determines which
overloaded function’s address will be obtained. In essence, the pointer’s declaration is
matched against those of the one whose address is used.

EXAMPLE:

Here is a program that contains two versions of a function called space(). The first
version outputs count number of spaces to the screen. The second version outputs count
number of whatever type of character is passed to ch. In main(), two function pointers

Page 62
Object Oriented Programming

are declared. The first one is specified as a pointer to a function having only one integer
parameter. The second is declared as a pointer to a function taking two parameters.

/* Illustrate assigning function pointers to overloaded functions.*/


#include<iostream.h>
using namespace std;

//Output count number of spaces.


void space (int count)
{
for( ; count; count--) cout << ‘ ‘;
}

// Output count number of chs.


void space(int count, char ch)
{
for( ; count; count--) cout << ch;
}
int main(()
{
/* Create a pointer to void function with one int parameter.*/
void (*fpl) (int);

/* Create a pointer to void function with one int parameter and one character parameter.
*/
void (*fp2) (int, char);

fp1 = space; // gets address of space(int)

fp2 = space; // gets address of space(int, char)

fp1(22); // output 22 spaces


cout << “l\n”;

fp2(30, ‘x’); // output 30 x’s


cout << “l\n”;

return 0;
Annamalai University
}
As the comments illustrate, the compiler is able to determine which overloaded function
to obtain the address of based upon how fp1 and fp2 are declared.

To review: When you assign the address of an overloaded function to a function


pointer, it is the declaration of the pointer that determines which function’s address is
assigned. Further, the declaration of the function pointer must exactly match one and

Page 63
Object Oriented Programming

only one of the overloaded functions. If it does not, ambiguity will be introduced, causing
a compile-time error.

3.2.6 The Basics Of Operator Overloading


Operator overloading resembles function overloading. In fact, operator
overloading is really just a type of function overloading. However, some additional rules
apply. For example, an operator is always overloaded relative to a user-defined type, such
as a class. Other differences will be discussed as needed.

When an operator is overloaded, that operator loses none of its original meaning.
Instead, it gains additional meaning relative to the class for which it is defined.
To overload an operator, you create an operator function. Most often an operator
function is a member or a friend of the class for which it is defined. However, there is a
slight difference between a member operator function and a friend operator function. The
first part of this chapter discusses the creation of member operator functions. Then friend
operator functions are discussed.

The general form of a member operator function is shown here:

return-type class-name::operator#(arg-list)
{
// operation to be performed
}
The return type of an operator function is often the class for which it is
defined.(However, an operator function is free to return any type.) The operator being
overloaded is substituted for the #. For example, if the + is being overloaded, the function
name would be operator+. The contents of arg-list vary depending upon how the
operator function is implemented and the type of operator being overloaded.

There are two important restrictions to remember when you are overloading an
operator. First, the precedence of the operator cannot be changed. Second, the number
of operands that an operator takes cannot be altered. For example, you cannot overload
the / operator so that it takes only one operand.

Most C++ operators can be overloaded. The only operators that you cannot
overload are shown here:

. :: .* ?
Annamalai University
Also, you cannot overload the preprocessor operators. (The .* operator is
highly specialized and is beyond the scope of this book.

Remember that C++ defines operators very broadly, including such thing as
the [] Subscript operators, the () function call operators, new and delete, and the. (dot)
and -> (arrow) operators. However, this chapter concentrates on overloading the most
commonly used operators.

Page 64
Object Oriented Programming

Except for the =, operator functions are inherited by any derived class.
However, a derived class is free to overload any operator it chooses (including those
overloaded by the base class) relative to itself.
You have been using two overloaded operators: << and >>. These operators
have been overloaded to perform console I/O. As mentioned, overloading these operators
to perform I/O does not prevent them from performing their traditional jobs of left shift
and right shift.

While it is permissible for you to have an operator function perform any


activity-whether related to the traditional use of the operator or no-it is best to have an
overloaded operator’s actions stay within the spirit of the operator’s traditional use.
When you create overloaded operators that stray form, this principle,. You run the risk of
substantially destructuring your program. For example, overloading the / so that the
phrase “I like C++” is written to a disk file 300 times is a fundamentally confusing
misuse of operator overloading!

The preceding paragraph notwithstanding, there will be times when you need to
use an operator in a way not related to its traditional usage. The two vest examples of
this are the << and >> operators, which are overloaded for console I/O. However, even
in these cases , the left and right arrows provide a visual “clued” to their meaning.
Therefore, if you need to overload an operator in a nonstandard way, make the greatest
effort possible to use an appropriate operator.

One final point: operator functions cannot have default arguments.

3.2.7 Overloading Binary Operators


When a member operator functions overloads a binary operator, the function will
have only one parameter. This parameter will receive the object that is on the right side of
the operator. The object on the left side is the object that generates the call to the operator
function and is passed implicitly by this.
It is important to understand that operator functions can be written with many
variations. The examples here and elsewhere in this chapter are not exhaustive, but they
do illustrate several of the most common techniques.

EXAMPLES:

Annamalai University
1.The following program overloads the + operator relative to the coord class. This class
is used to maintain X, Y coordinates.

//Overload the + relative to coord class.


#include<iostream.h>
using namespace std;

class coord {
int x, y; // coordinates values
public:

Page 65
Object Oriented Programming

coord( ) {x=0, y=0;}


coord(int i, int j) {x=i; y=j;}
void get_xy(int &i, int &j) {i=x; j=y;}
coord operator+(coord ob2);
};

//overload + relative to coord class.


coord coord::operator+(coord ob2)
{
coord temp;
temp.x = x + ob2.x;
temp.y = y+ob2.y;

return temp;
}

int main( )
{
coord o1(10, 10), o2(5, 3), o3;
int x, y;

o3= o1 + o2; //add two objects – this calls operator+( )

o3.get_xy(x, y);
cout<<”(o1+o2) x: “<<x<<”, y: ”<<y<<”\n”;

return 0;
}

This program displays the following:


(o1 + o2) x: 15, y:13

Let’s look closely at this program. The operator+( ) function returns an objects of
type coord that has the sum of each operand’s X coordinates in x and the sum of the Y
coordinates in y. Notice that a temporary object called temp is used inside operator+( )
to hold the result, and it is returned. Notice also that neither operand is modified. The
Annamalai University
reason for temp is easy to understand. In this situation(as in most), the + has been
overloaded in a manner consistent with its normal arithmetic use. Therefore, it was
important that neither operand be changed. For example, when you add 10+4, the result is
14, but neither that 10 nor the 4 is modified. Thus, a temporary object is needed to hold
the result.

The reason that the operator+( ) function returns an object of type coord is that
it allows the result of the addition of coord objects to be used in larger expressions. For
example, the statement
o3 = o1 + o2;

Page 66
Object Oriented Programming

is valid only because the result of o1 + o2 is a coord object that can be assigned to o3. If
a different type had been returned, this statement would have been invalid. Further, by
returning a coord object, the addition operator allows a string of additions.

For example, this is a valid statement:


o3 = o1 + o2 +o1 + o3;

Although there will be situations in which you want an operator function to return
something other than an object for which it is defined, most of the time operator functions
that you create will return an object of their class. The major exception to this rule is
when the relational and logical operators are overloaded.
One final point about this example. Because a coord object is returned, the
following statement is also perfectly valid:

(o1+o2) .get_xy(x, y);

Here the temporary object returned by operator+( ) is used directly. Of course, after this
statement has executed, the temporary object is destroyed.

2. The following versions of the preceding program overloads the – and the =
operators relative to the coord class.

//overload the +,-, and = relative to coord class.


#include<iostream.h>
using namespace std;
class coord {
int x, y; //coordinates value
public:
coord( ) {x=0;y=0;}
coord(int i, int j) {x=i; y=j;}
void get_xy(int &i, int &j) {i=x; j=y;}
coord operator+(coord ob2);
coord operator-(coord ob2);
coord operator=(coord ob2);
};

Annamalai University
//Overload + relative to coord class
coord coord::operator+(coord ob2)
{
coord temp;

temp.x = x + ob2.x;
temp.y = y + ob2.y;

return temp;
}

Page 67
Object Oriented Programming

//overload – relative to coord class


coord coord::operator-(coord ob2)
{
coord temp;
temp.x = x - ob2.x;
temp.y = y - ob2.y;
return temp;
}

//Overload = relative to coord.


coord coord::operator=(coord ob2)
{
x = ob2.x;
y = ob2.y;

return *this; //return the object that is assigned


}

int main( )
{
coord o1(10, 10), o2(5, 3), o3;
int x, y;

o3= o1 + o2; //add two objects – this calls operator+( )


o3.get_xy(x, y);
cout<<”(o1+o2) x: “<<x<<”, y: ”<<y<<”\n”;

o3= o1 - o2; //subtract two objects


o3.get_xy(x, y);
cout<<”(o1-o2) x: “<<x<<”, y: ”<<y<<”\n”;

o3= o1; //assign an objects


o3.get_xy(x, y);
cout<<”(o3=o1) x: “<<x<<”, y: ”<<y<<”\n”;

return 0;
} Annamalai University
The operator-( ) function is implemented similarly to operator+( ). However, the
above example illustrate a crucial point when you are overloading an operator in which
the order of the operands is important. When the operator+( ) function was created, it did
not matter which ordered the operands where in.(That is, A+B is the same as B+A).
However, the subtraction operation is order dependent. Therefore, to correctly overload
the subtraction operator, it is necessary to subtract the operand on the right from the
operand on the left. Because it is the left operand that generates the call to operator-(
),the subtraction must be in this order:

Page 68
Object Oriented Programming

X – ob2.x;

REMEMBER:
When a binary operator is overloaded, the left operand is passed implicitly to the
function and the right operand is passed as an argument.

Now look at the assignment operator function. The first thing you should notice is
that the left operand(that is, the object being assigned a value) is modified by the
operation. This is in keeping with the normal meaning of assignment. The second thing to
notice is that the function returns this. That is,theoperator=( ) function returns the object
that is being assigned to. The reason for this is to allow a series of assignments to be
made. As you should know, in C++, the following type of statement is syntactically
correct(and,indeed,very common):

a = b = c =d = 0;

By returning *this, the overloaded assignment operator allows object of type


coord to be used in a similar fashion, For example, this is perfectly valid:

o3 = o2 = o1;

Keep in mind that there is no rule that required on overloaded assignment


function to return the object that receives the assignment. However, if you want the
overloaded = to behave relative to its class the way it does for the built-in types, it must
returns *this.

3.2.8 Overloading The Relational And Logical Operators


It is possible to overload the relational and logical operators. When you overload
the relational and logical operators so that they behave in their traditional manner, you
will not want the operator functions to return an object of the class for which they are
defined. Instead, they will return an integer that indicates either true or false. This is not
only allows these operator functions to return a true/false value, it also allows the
operators to be integrated into larger relational and logical expressions that involve other
type of data.

Note:
Annamalai University
If you are using a modern C++ compiler, you can also have an overloaded
relational or logical operator function return a value of type bool, although there is no
advantage to doing so. As explained in Chapter 1, the bool type defines only two
values:true and false.
These values are automatically converts into nonzero and 0 values. Integer nonzero and 0
values are automatically converted into true and false.
Example:
1.In the following program, the = = and && operator are overloaded:

//overload the == and && relative to coord class.

Page 69
Object Oriented Programming

#include<iostream.h>
using namespace std;
class coord {
int x, y; // coordinates values.
public:
coord( ) { x=0; y=0}
coord(int i, int j) { x=i; y=j; }
void get_xy(int &i, int &j) {i=x; j=y;}
int operator= = (coord ob2);
int operator&& (coord ob2);
};
//overloaded the = = operator for coord.
int coord::operator = =(coord ob2)
{
return x = = ob2.x && y= = ob2.y;
}
//overloaded the && operator for coord.
int coord::operator && (coord ob2)
{
return (x && ob2.x) && (y && ob2.y);
}

int main( )
{
coord o1(10, 10), o2(5, 3), o3(10, 10), o4(0, 0);

if(o1 = = o2) cout<<”o1 same as o2\n”;


else cout<<”o1 and o2 differ\n”;

if(o1 = = o3) cout<<”o1 same as o3\n”;


else cout<<”o1 and o3 differ\n”;

if(o1 && o2) cout<<”o1 && o2 is true\n”;


else cout<<”o1 && o2 is false\n”;

if(o1 && o4) cout<<”o1 && o4 is true\n”;


Annamalai University
else cout<<”o1 && o4 is false\n”;

return 0;
}

3.2.9 Overloading A Unary Operator


Overloading a unary operator is similar to overloading a binary operator except
that there is only one operand to deal with. When you overload a unary operator using a
member function, the function has no parameters. Since there is only one operand, it is

Page 70
Object Oriented Programming

this operand that generates the call to the operator function. There is no need for another
parameter.

EXAMPLES:

1.The following program overloads the increment operator( + + ) relative to the coord
class:

//Overload + + relative to the coord class.


#include<iostream.h>
using namespace std;

class coord {
int x, y; //coordinate values

public:
coord( ) { x=0; y=0}
coord(int i, int j) { x=i; y=j; }
void get_xy(int &i, int &j) {i=x; j=y;}
coord operator+ + ( );
};

//Overload + + for coord class.


coord coord::operator+ +( )
{
x++;
y++;
return *this;
}

int main( )
{
coord o1(10, 10);
int x, y;

++o1; //increment an object


Annamalai University
o1.get_xy(x, y);
cout<<”(++o1) X: “<<x << “, Y: “<<y<<”\n”;

return 0;
}

Since the increment operator is designed to increase its operand by 1, the overloaded + +
modifies the object it operates upon. The function also returns the object that it
increments.
This allows the increment operator to be used as a part of large statement, such as this:

Page 71
Object Oriented Programming

o2= ++o1;

As with the binary operators, there is no rule that says you must overload a unary
operator so that it reflects its normal meaning. However, most of the time this is what you
will want to do.

2. In early versions of C++, when an increment or decrement operator was


overloaded, there was no way to determine whether an overloaded + + or – preceded or
followed its operand. That is, assuming the preceding program, these two statements
would have been identical:

o1++;
++o1;
However, the modern specification for C++ has defined a way by which the
compiler can distinguish between these two statements. To accomplish this, create two
versions of the operator++( ) function. The first is defined as shown in the preceding
example. The second is declared like this:

coord coord::operator++(int notused);

If the ++ precedes its operand, the operator++( ) function is called. However, if


the ++ follows its operand, the operator++( int notused) function is used. In this case,
notused will always be passed the value 0. Therefore, if the difference between prefix
and postfix increment or decrement is important to your class objects, you will need to
implement both operator functions.

3.As you know, the minus sign is both a binary and a unary operator in C++. You
might be wondering how you can overload it so that it retains both of these uses relative
to a class that you create. The solution is actually quite easy: you simply overload it
twice, once as a binary operator and once as a unary operator. This program shows how:

//Overload the – relative to coord class.


#include<iostream.h>
using namespace std;

class coord { Annamalai University


int x, y; //coordinates value
public:
coord( ) {x=0;y=0;}
coord(int i, int j) {x=i; y=j;}
void get_xy(int &i, int &j) {i=x; j=y;}
coord operator-(coord ob2); //binary minus
coord operator-( ); //unary minus
};

Page 72
Object Oriented Programming

//overload – relative to coord class


coord coord::operator-(coord ob2)
{
coord temp;
temp.x = x - ob2.x;
temp.y = y - ob2.y;
return temp;
}

//Overload unary - for coord class.


coord coord::operator-( )
{
x = -x;
y = -y;

return *this;
}

int main( )
{
coord o1(10, 10), o2(5, 7);
int x, y;
o1 = o1 – o2; //subtraction
o1.get_xy(x, y);
cout<<”(o1 – o2) X: “<< x << “ , Y: “ << y << “\n”;

o1 = -o1; //negative
o1.get_xy(x, y);
cout<<”(-o1) X: “<<x<< “ , Y: “<<y<<”\n”;

return 0;
}

As you can see, when the minus is overloaded as a binary operator, it takes one
parameter. When it is overloaded as a unary operator, it takes no parameter. This
difference in the number of parameter is what makes it possible for the minus to be
Annamalai University
overloaded for both operation. As the program indicates, when the minus sign is used as a
binary operator, the operator-( coord ob2) function is called. When it is used as a unary
minus, the operator-( ) function is called.

3.2.10 Using Friend Operator Functions


As mentioned earlier, it is possible to overload an operator relative to a class by
using a friend rather than a member function. As you know, a friend function does not
have a this pointer. In the case of a binary operator, this means that a friend operator
function is passed both operands explicitly. For unary operators, the single operand is

Page 73
Object Oriented Programming

passed. All other things being equal, there is no reason to use a friend rather than a
member operator function, with one important exception, which is discussed in the
examples.

REMEMBER:
You cannot use a friend to overload the assignment operator. The assignment
operator can be overloaded only by a member operator function.

EXAMPLES:

1.Here operator+( ) is overloaded for the coord class by using a friend function:

//overload the + relative to coord class using a friend.


#include<iostream.h>
using namespace std;

class coord {
int x, y; //coordinates value
public:
coord( ) {x=0;y=0;}
coord(int i, int j) {x=i; y=j;}
void get_xy(int &i, int &j) {i=x; j=y;}
friend coord operator+(coord ob1, coord ob2);
};

//overload + using a friend.


coord operator+(coord ob1,coord ob2)
{
coord temp;

temp.x = ob1.x + ob2.x;


temp.y = ob1.y + ob2.y;

return temp;
}
int main( )
{ Annamalai University
coord o1(10, 10), o2(5, 3), o3;
int x, y;

o3 = o1 + o2; //add two object – this calls operator+( )


o3.get_xy(x, y);
cout<< “(o1 + o2) X: “<< x << “ , Y: “<<y<<”\n”;

return 0;
}

Page 74
Object Oriented Programming

Notice that the left operand is passed to the first parameter and the right operand
is passed to the second parameter.

2. Overloading an operator by using a friend provides one very important features


that member functions do not. Using a friend operator function, you can allow objects to
be used in operations involving built-in types in which the built-in type is on the left side
of the operator. As you say earlier in this chapter, it is possible to overload a binary
member operator function such that the left operand is an object and the right operand is a
built-in type. But it is not possible to use a member function to allow the built-in type to
occur on the left side of the operator. For example, assuming an overloaded member
operator function, the first statement shown here is legal; the second is not:

ob1 = ob2 + 10; //Legal


ob1 = 10 + ob2; //illegal

While it is possible to organize such statements like the first, always having to
make sure that object is on the left side of the operand and the built-in type on the right
can be a cumbersome restriction. The solution to this problem is to make the overloaded
operator functions friends and define both possible situations.
As you know, a friend operator function is explicitly passed both operands. Thus,
it is possible to define one overloaded friend function so that the left operand is an object
and the right operand is the other type. Then you could overload the operator again with
the left operand being the built-in type and the right operand being the object. The
following program illustrate this method:

//use friend operator functions to add flexibility.


#include<iostream.h>
using namespace std;

class coord {
int x, y; //coordinates value
public:
coord( ) {x=0;y=0;}
coord(int i, int j) {x=i; y=j;}
void get_xy(int &i, int &j) {i=x; j=y;}
friend coord operator+(coord ob1,int i);

};
Annamalai University
friend coord operator+(int i,coord ob1);

//overload for ob + int..


coord operator+(coord ob1,int i)
{ coord temp;
temp.x = ob1.x + i;
temp.y = ob1.y + i;
return temp;
}

Page 75
Object Oriented Programming

//overload for int + ob.


coord operator+(int i,coord ob1)
{
coord temp;
temp.x = ob1.x + i;
temp.y = ob1.y + i;
return temp;
}

int main()
{
coord o1(10 , 10);
int x , y;
o1 = o1 +10;// object + integer
o1.get_xy(x,y);
cout<<”(o1+10) X:”<<x<<”,Y: “<<y<<”\n”;
o1 = 99 + o1;// object + integer
o1.get_xy(x,y);
cout<<”(99 + o1) X:”<<x<<”,Y: “<<y<<”\n”;

return 0;
}

As a result of overloading friend operators functions for both situations, both of


these statements are now valid:

o1 = o1 + 10;
o1 = 99 + o1;

2.If you want to use a friend operator function to overload either the + + or - -
unary operator, you must pass the operand to the function as the reference parameter.
This is because friend functions do not have this pointers. Remember that the increment
or decrement operators imply that the operand will be modified. However, if you
overload these operators by using a friend that uses a value parameter, any modifications
that occur to the parameter inside the friend operator function will not affect the object
Annamalai University
that generated the call. And since no pointer the object is passed implicitly(that is, there is
no this pointer) when a friend is used, there is no way for the increment or decrement to
affect the operand.
However, if you pass the operant to the friend as a reference parameter, changes
that occur inside the friend function affect the object that generates the call. For example,
here is a program that overloads the + + operator by using a friend function:

//Overload the + + using a friend.


#include<iostream.h>
using namespace std;

Page 76
Object Oriented Programming

class coord {
int x, y; //coordinates values
public:
coord( ) { x=0; y=0;}
coord(int i, int y) { x=i; y=j; }
void get_xy(int &i, int &j) { i=x; j=y; }
friend coord operator+ +(coord &ob);
};

//Overload + + using a friend.


coord operator + +(coord &ob) //use reference parameter
{
ob.x+ +;
ob.y+ +;

return ob; //return object generating the call


}

int main( )
{
coord o1(10, 10);
int x, y;

++o1; //o1 is passed by reference


o1.get_xy(x, y);
cout<< “(++o1) X: “<< x << ”, Y:” << y << “\n”;

return 0;
}

If you are using a modern compiler, you can also distinguish between the prefix
and postfix forms of the increment or decrement operators when using a friend operator
function in much the same way you did when using member functions. You simply add
an integer parameter when defining the postfix version. For example, here are the
prototypes for both the prefix and postfix versions of the increment operator relative to
the coord class.
Annamalai University
coord operator++(coord &ob); // prefix
coord operator++(coord &ob, int notused); // postfix

If the + + precedes its operand, the operator++(coord &ob) function is called.


However, if the + + follows its operand, the operator+ +(coord &ob, int notused)
function is used. In this case, notused will be passed the value 0.

Page 77
Object Oriented Programming

3.2.11 A Closer Look At The Assignment Operator


As you have seen, it is possible to overload the assignment operator-relative to a
class. By default, when the assignment operator is applied to an object, a bitwise copy of
the object on the right is put into the object on the left. If this is what you want, there is
no reason to provide your own operator = ( ) function. However, there are cases in
which a strict bitwise copy is not desirable. You saw some examples of this in Chapter 3,
in cases in which an object allocates memory. In these types of situations, you will want
to provide a special assignment operation.

EXAMPLES:

1.Here is another version of the strtype class that you have seen in various forms
in the preceding chapters. However, this version overloads the = operator so that the
pointer p is not overwritten by an assignment operation.

#include<iostream.h>
#include<cstring.h>
#include<cstdlib.h>
using namespaces std;

class strtype {
char *p;
int len;
public:
strtype(char *s)
~strtype( ){
cout<<”Freeing “<<(unsigned) p <<”\n”;
delete [] p;
}
char *get() { return p;}
strtype &operator=(strtype &ob);
};

strtype::strtype(char *s)
{
int l;
Annamalai University
l = strlen(s) + 1;
p = new char [1];
if(!p) {
cout<<”Allocation error\n”;
exit(1);
}

len = 1;
strcpy ( p , s);
}

Page 78
Object Oriented Programming

//Assign an object.
strtype &strtype::operator=(strtype &ob)
{
//see if more memory is needed
if(len < ob.len ) {// need to allocate more memory
delete [] p;
p = new char [ ob.len ];
if(!p) {
cout<<”Allocation error\n”;
exit(1);
}
}
len = ob.len;
strcpy(p, ob.p);
return *this;
}

int main( )
{
strtype a(“Hello”),b(“There”);
cout<<a.get( ) << “\n”;
cout<<b.get( ) << “\n”;
a = b; // now p is not overwritten
cout<< a.get( ) <<”\n”;
cout << b.get( ) << “\n”;
return 0;
}

As you can see, the overloaded assignment operator prevents p from being
overwritten. It first checks to see if the object on the left has allocated enough memory to
hold the string that is being assigned to it. If it hasn’t, that memory is freed to another
portion is allocated. Then the string is copied to that memory and the length is copied into
len.
Notice two other important features about the operator = ( ) function. First , it
takes a reference parameter. This prevent the copy of the object on the right side of the
Annamalai University
assignment from begin made. As you know from previous Chapters, when a copy of an
object is made when passed to a function, that copy is destroyed when the function
terminates. In the case, destroying the copy would call the destructor function, which
would free p. However, this is the same p still needed by the object used as an argument.
Using a reference parameter prevents this problem.

The second important feature of the operator = ( ) function is that it returns a


reference, not an object. The reason for this is the same as the reason it used a reference
parameter. When a function returns an object, a temporary object is created that is
destroyed after-the return is completed. However, this means that the temporary object’s

Page 79
Object Oriented Programming

destructor will be called, causing p to be freed, but p (and the memory it points to) is still
needed by the object being assigned a value. Therefore, by returning a reference, you
prevent a temporary object from being created.

3.2.12 Overloading The [ ] Subscript Operator


The last operator that we will overload is the [ ] array subscripting operator. In
C++, the [ ] is considered a binary operator for the purpose of overloading. The [ ] can
be overloaded only by a member function. Therefore, the general form of a operator[ ]
( ) function is as shown here:

type class-name::operator [ ] (int index)


{
//…
}

Technically, the parameter does not have to be of type int, but operator [ ] ( ) functions
are typically used to provide array subscripting and as such an integer value is generally
used.
To understand how the [ ] operator works, assume that an object called 0 is
indexed as shown here:

0[9]

This index will translate into the following call to the operator [ ] ( ) function:

0.operator [ ] ( 9)

That is, the value of the expression within the subscripting operator is passed to the
operator [ ] ( ) function in its explicit parameter. The this pointer will point to 0, the
object that generated the call.

EXAMPLES:

In the following program, arraytype declares an array of five integers. Its constructor
function initializes each member of the array. The overloaded operator [ ] ( ) function
Annamalai University
returns the value of the elements specified by its parameter.

#include<iostream.h>
using namespace std;

const int SIZE = 5;

class arraytype {
int a[SIZE];
public:

Page 80
Object Oriented Programming

arraytype( ) {
int i;
for(i=0; i<SIZE; i++) a[i] = i;
}
int operator [ ] (int i) { return a[i]; }
};

int main( )
{
arraytype ob;
int i;

for(i=0; i<SIZE; i++)


cout << ob[i] << “ “;
return 0;
}

This program displays the following output:


0 1 2 3 4

The initialization of the array a by the constructor in this and the following programs is
for the sake of illustration only. It is not required.

2. It is possible to design the operator[ ] ( ) function in such a way that the [ ] can
be used on both the left and right sides of an assignment statement. To do this, return a
reference to the element being indexed. For example, this program makes this change and
illustrates its use:

#include<iostream.h>
using namespace std;

const int SIZE = 5;

class arraytype {
int a[SIZE];
public:
Annamalai University
arraytype( ) {
int i;
for(i=0; i<SIZE; i++) a[i] = i;
}
int &operator[ ] (int i) { return a[i]; }
};

int main( )
{
arraytype ob;

Page 81
Object Oriented Programming

int i;

for(i=0; i<SIZE; i++)


cout << ob[i] << “ “;

cout << “\n”;

//add 10 to each element in the array


for(i=0; i<SIZE; i++)
ob[i] = ob[i]+10; // [ ] on left of =

for(i=0; i<SIZE; i++)


cout << ob[i] << “ “;

return 0;
}

This program displays the following output:


0 1 2 3 4
10 11 12 13 14

Because the operator[ ]( ) function now returns a reference to the array element
indexed by i, it can be used on the left side of an assignment to modify an element of the
array. (Of course, it can still be used on the right side as well.) As you can see, this makes
objects of arraytype act like normal arrays.

3. One advantage of being able to overload the [ ] operator is that it allows a better
means of implementing safe array indexing. Earlier in this book you saw a simplified
way to implement a safe array that relied upon functions such as get( ) and put( ) to
access the elements of the array. Here you will see a better way to create a safe array that
utilizes an overloaded [ ] operator. Recall that a safe array is an array that is encapsulated
within a class that performs bounds checking. This approach prevents the array
boundaries from being overrun. By overloading the [ ] operator for such an array, you
allow it to be accessed just like a regular array.
To create a safe array, simply add bounds checking to the operator[ ]( ) function.
The operator[ ]( ) must also return a reference to the element being indexed. For
Annamalai University
example, this program adds a range check to the previous array program and proves that
it works by generating a boundary error:

//A safe array example.


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

const int SIZE = 5;

Page 82
Object Oriented Programming

class arraytype {
int a[SIZE];
public:
arraytype( ) {
int i;
for(i=0; i<SIZE; i++) a[i] = i;
}
int &operator [ ] (int i);
};

// Provide range checking for arraytype.


int &arraytype::operator[ ] (int i)
{
if(i<0 || i>SIZE-1) {
cout<< “\n INDEX value of “ ;
cout<< i << “is out of bounds.\,”;
exit(1);
}
return a[i];
}

int main( )
{
arraytype ob;
int i;

// this is OK
for(i=0; i<SIZE; i++)
cout << ob[i] << “ “;

/* this generates a run-time error because


SIZE + 100 is out of range */
ob[SIZE + 100] = 99 ; // error!

return 0;
}
Annamalai University
In this program, When the statement

Ob[SIZE + 100] = 99;

Executes, the boundary error is intercepted by operator[ ] ( ) and the program is


terminated before any damage can be done.
Because the overloading of the [ ] operator allows you to create safe arrays that
look and act just like regular arrays, they can be seamlessly integrated into your
programming environment. But be careful. A safe array adds overhead that might not be

Page 83
Object Oriented Programming

acceptable in all situations. In fact, the added overhead is why C++ does not perform
boundary checking on arrays in the first place. However, in applications in which you
want to be sure that a boundary error does not take place, a safe array will be worth the
effort.

3.3) Revision Points


COPY CONSTRUCTOR:
The copy constructor that creates a new class object from an existing object of the
same class.

DEFAULT ARGUMENT:
An argument value that is specified in a function declaration is used if the
corresponding actual argument is omitted when function is called.

OVERLOADING:
A feature that allows a function or operator to be given more than one definition
is called overloading.

CONSTRUCTOR OVERLOADING:
All the constructors have the same name as of the class and they differ only in
terms of their signature.

3.4) Intext Questions


1) Can a ‘friend’ function be used for overloading assignment operator?
Justify your answer.
2) Use an overloaded ++ operator to increment data
3) Concatenate two strings using operator overload.
4) Design three separate constructors for a class as indicated below:
 No arguments.
 Two arguments.
 One argument.

5) How can logical and relational operators be overloaded? Give example.


6)
7)
Annamalai University
Write a program to overload the subscript () operator.
Create a class FLOAT that contains one float.
8) How can you resolve the ambiguity in overloading?

3.5) Summary

 The most frequent use of overloaded constructor functions is to provide option of


either giving an object an initializing or not.
 Once you have defined both parameterized and parameter less constructors you
can create initialized and non-initialized arrays.

Page 84
Object Oriented Programming

 Similar to normal functions, constructors may be overloaded.


 When an object is created and initialized at the same time, a copy constructor gets
called.
 Default argument allows you to give a parameter default value when no
corresponding argument is specified when function is called.
 Overloading caused ambiguity can be introduced through type conversions,
reference parameters, and default arguments.
 When obtaining the address of an overloaded function it is the way the pointer is
declared that determines which overloaded function’s address will be obtained
Using overloading feature we can add two user defined data types such as objects with
the same syntax, just as basic data type.

3.6) Terminal Exercises


1. The ______ only applies to initialization and not to assignments.
2. __________ gives a parameter a default value when no argument is specified
when the function is called.
3. Default arguments must be constant or ________ they cannot be local variables.
4. When a member operator functions overloads a binary operator, the function will
have only________ parameter.
5. When a binary operator is overloaded the left operand is passed implicitly to
function and right operand as ___________.
6. __________ operator cannot be used to overload using friend function.
7. When an initialization occurs, the compiler will automatically provide a
________.

3.7) Supplementary Materials


Teach yourself C++, Third edition, Herbert Scheldt, Tata McGraw Hill

3.8) Assignments
6. Create a class ‘sqmatrix’ of the type square matrix of real number and
overload the operator ‘=’ to find the sum of the two objects of the type
‘sqmatrix’.

Annamalai University
7. Define a class string. Use overload == operator to compare two strings.

3.9) Reference Books / E-References


8. C++ Black Book: A Comprehensive Guide to C++ Mastery by Steven Holzner
9. Real-time 3D Character Animation with Visual C++ (Book & CD-ROM) by
Nik Lever
10. http://www.cplusplus.com/
11. http://www.codersource.net/codersource_cppprogramming.html

Page 85
Object Oriented Programming

3.10) Learning Activities


1. Define a class ‘complex-no’ which has 2 real numbers as private variables
one represents the real part and the other for complex part. Define a
constructor to initialize the object.
2. Write a function to print three lines of varying lengths using default
arguments.
3. Concatenate two strings using operator overloading.

3.11) Keywords
OVERLOADING: A language feature that allows a function or operator to be
given more than one definition.

COPY CONSTRUCTOR: The constructor that creates a new class object from an
existing object of the same class.

DEFAULT ARGUMENT: An argument value that is specified in a function


declared and is used if the actual argument is omitted when the function is called.

Annamalai University

Page 86
Object Oriented Programming

UNIT-IV

4.0) Introduction
In this chapter you will get to know the advance features of C++. A class from
which other classes are derived, it is called base class. There will be times when you want
to keep a member of a base class private, but allow a derived class access to it. To
accomplish this, C++ includes the protected access specifier.

It is possible for the base class, the derived class, or both to have constructor and /
or destructor functions. Another feature that allows a derived class to have more than one
base class is called multiple inheritances. The C++, I/O system allows you to format I/O
operations. This method uses special functions called I/O Manipulators.

4.1) Objectives
In this chapter you will learn inheritance and the different access mechanisms. You will
learn the implementation of virtual base class. At the end of the chapter you will also
learn certain Input Output operators.

4.2) Content
4.2.1 Base Class Access Control

When one class inherits another it uses this general form:

Class derived-class-name : access base-class-name {


//…
}
Here access is one of three keywords: public, private, or protected. A discussion
of the protected access specifier is deferred until the next section of this chapter. The
other two are discussed here.
The access specifier determines how elements of the base class are inherited by
the derived class. When the access specifier for the inherited base class is public, all
Annamalai University
public members of the base become public members of the derived class. If the access
specifier is private, all public members of the base class become private members of the
derived class.
In either case, any private members of the base remain private to it and are
inaccessible by the derived class.
It is important to understand that if the access specifier is private, public
members of the base become private members of the derived class, but these members
are still accessible by member functions of the derived class.

Technically, access is optional. If the specifier is not present ,it is private by


default if the derived class is a class. If the derived class is a struct, public is the default

Page 87
Object Oriented Programming

in the absence of an explicit access specifier. Frankly, most programmers explicitly


specify access for the sake of clarity.

EXAMPLES
1. Here is a short base class and a derived class that inherits it (as public):

#include<iostream.h>
using namespace std;
class base {
int x;
public :
void setx(int n) { x=n; }
void showx( ) { cout<<x<<’\n’; }
};
//Inherit as public.
class derived : public base
{
int y;
public :
void sety( int n) { y=n; }
void showy( ) { cout<<y<<’\n’; }
};
int main( )
{
derived ob;
ob.setx(10); //access member of base class
ob.sety(20); //access member of derived class
ob.showx( ); //access member of base class
ob.showy( ); //access member of derived class
return 0;
}
As this program illustrates, because base is inherited as public, the public
members of base-setx( ) and showx( )- become public members of derived and are,
therefore, accessible by any other part of the program. Specifically, they are legally call
within
main( ).
Annamalai University
2. It is important to understand that just because a derived class inherits a base as public,
it does not mean that the derived class has access to the base’s private members. For
example is incorrect:

class base {
int x;
public:
void setx(int n) {x=n; }
void showx( ) {cout << x<< ‘\n’;}

Page 88
Object Oriented Programming

};

//Inherit as public – this has an error!


class derived : public base{
public:
void sety(int n) {y=n;}
/* Cannot access private member of base class.
X is a private member of base and not available within derived. */
Void show_sum( ) {cout <<x+y << ‘\n’; }//Error!
Void showy( ) {cout << y << ‘\n’;}
};

In this example, the derived class attempts to access x, which is a private member
of base. This is an error because the private parts of a base class remain private to it no
matter how it is inherited.

3. Here is a variation of the program shown in Example 1; this time derived


inherits base as private. This change causes the program to be in error, as indicated in
the comments

//This program contains an error.


#include<iostream.h>
using namespace std;
class base {
int x;
public:
void setx(int n) {x=n;}
void showx( ) {cout << x << ‘\n’;}
};
// Inherit base a private.
Class derived : private base {
int y;
public:
void sety(int n) {y=n;}
void showy( ) {cout << y << ‘\n’;}
};

int main( )
Annamalai University
{
derived ob;
ob.setx(10); //ERROR –now private to derived class
ob.sety(20); //access member of derived class-OK

ob.showx( ); // ERROR –now private to derived class


ob.showy( ); //access member of derived class-OK

Page 89
Object Oriented Programming

return 0;
}

As the comments in this (incorrect) program illustrate, both showx( ) and setx( )
become private to derived and are not accessible outside of it .

Keep in mind that showx( ) and setx( ) are still public within base no matter how
they are inherited by some derived class. This means that an object of type base could
access these functions anywhere. However, relative to objects of type derived, they
become private. For example, given this fragment:

base base_ob;
base_ob.stex(1);// is legal because base_ob is of type base

the call to setx( ) is legal because setx( ) is public within base.

4.2.2 Using Protected Members


As you know from the preceding section, a derived class does not have access to the
private members of the base class. This means that if the derived class needs access to
some member of the base, that member must be public. However, there will be times
when you want to keep a member of a base class private but still allow a derived class
access to it. To accomplish this goal, C++ includes the protected access specifier.

The protected access specifier is equivalent to the private specifier with the sole
exception that protected members of a base class are base or derived classes, protected
members are not accessible.

The protected access specifier can occur anywhere in the class declaration,
although typically it occurs after the (default) private members are declared and before
the public members. The full general form of a class declaration is shown here:

Class class-name {
// private members
protected //optional
// protected members
public:
//public members
};
Annamalai University
When a protected member of a base class is inherited as public by the derived
class, it becomes a protected member of the derived class. If the base is inherited as
private, the protected member of the base becomes a private member of the derived class.

A base class can also be inherited as protected by derived class. When this is the
case, public and protected members of the base become protected members of the derived

Page 90
Object Oriented Programming

class. (Of course, private members of the base class remain private to it and or not
accessible by the derived class.)

The protected access specifier can also be used with structures.

EXAMPLES
1. This program illustrates how public, private, and protected members of a class can
be accessed:
#include<iostream.h>
using namespace std;
class samp{
// private by default
int a;
protected; // still private relative to samp
int b;
public:
int c;

samp(int n,int m) {a=n;b=m;}


int geta( ) {return a;}
int getb( ) {return b;}
};

int main( )
{
samp ob(10,20);
// ob.b=99; Error! b is protected and thus private ob.c=30;//OK, c is public

cout << ob.geta( )<< ‘ ‘;


cout <<ob.getb( )<< ‘ ‘ << ob.c <<’\n’;

return 0;
}

As you can see, the commented-out line is not permissible in main( ) because b is
protected and is thus still private to samp.
Annamalai University
2. The following program illustrates what occurs when protected members are
inherited as public:

#include<iostream.h>
using namespace std;
class base {
protected; // private to base
int a,b;// but still accessible by derived

Page 91
Object Oriented Programming

public:
void setab(int n,int m) {a=n;b=m;)
};
class derived : public base {
int c;
public:
void setc(int n){c=n;}
//.this function has access to a and b from base
void showabc( ){
cout <<a<<’ ‘<<b<<’ ‘<<c<<’\n’;
}
};
int main( )
{
derived ob;
/* a and b are not accessible here because they are private to both base and derived.*/
ob.setab(1,2);
ob.setc(3);

ob.showabc( );
return 0;
}

Because a and b are protected in base and inherited as public by derived, they are
available form use by member functions of derived. However, outside of these two
classes, a and b are effectively private and inaccessible.

4.2.3 Constructors, Destructors And Inheritance


It is possible for the base class, the derived class, or both to have constructor
and/or
destructor functions. Several issues that relate to these situations are examined in this
section.

When a base class and a derived class both have constructor and destructor
functions, the constructor functions are executed in order of derivation. The destructor
functions are executed in reverse order. That is, the base class constructor is executed
Annamalai University
before the constructor in the derived class. The reverse is true for destructor functions:
the derived class’s destructor is executed before the base class’s destructor.

If you think about it, it makes sense that constructor functions are executed in
order of derivation. Because a base class has no knowledge of an derived class, any
initialization it performs is separated from and possibly prerequisite to any initialization
performed by the derived class. Therefore, it must be executed first.

On the other hand, a derived class’s destructor must be executed before the
destructor of the base class because the base class underlies the derived class. If the base

Page 92
Object Oriented Programming

class’s destructor were executed first, it would imply the destruction of the derived class.
Thus, the derived class’s destructor must be called before the object goes out of the
existence.
So far, none of the preceding examples have passed arguments to either a derived
or
base class constructor. However, it is possible to do this. When only the derived class
takes on initialization, arguments are passed to the derived class’s constructor in the
normal fashion. However, if you need to pass an argument to the constructor of the base
class, a little more effort is needed. To accomplish this, a chain of argument passing is
established. First, all necessary arguments to both the base class and the derived class are
passed to the derived class’s constructor. Using an expanded form of the derived class’s
constructor declaration, you then pass the appropriate arguments along to the base class.
The syntax for passing along an argument from the derived class to the base class is
shown here:

derived-constructor[arg-list]:base[arg-list]{
//body of derived class constructor
}

Here base is the name of the base class. It is permissible for both the derived class
and the base class to use the same argument. It is also possible for the derived class to
ignore all arguments and just pass them along to the base.

EXAMPLES:

1. Here is a very short program that illustrates when base class and derived class
constructor and destructor functions are executed:

#include<iostream.h>
using namespace std;

class base {
public:
base( ) { cout << “Constructing base class \n”; }
~base( ) { cout << “ Destructing base class \n” }
};
Annamalai University
class derived : public base {
public:
derived( ) { cout << “Constructing derived class \n”; }
~derived( ) { cout << “ Destructing derived class \n” }
};

int main( )
{
derived 0;

Page 93
Object Oriented Programming

return 0;
}

This program displays the following output:

Constructing base class


Constructing derived class
Destructing derived class
Destructing base class.

As you can see, the constructors are executed in order of derivation and the destructors
are executed in reverse order.

2. This program shows how to pass an argument to a derived class’s constructor:

#include <iostream.h>
using namespace std;

class base{
public:
base() {cout<<”constructing base class \n”;}
~base () {cout<<”destructing base class \n”; }
};
class derived: public base{
int j;
public:
derived(int n) {
cout<<”constructing derived class \n”;
j=n;
}
~derived() {cout<<”destructing derived class \n”;}
void show j(){cout <<j<<’n’;}
};
int main()
{
derived 0(10);
0.showj();
Annamalai University
return 0;
}
Notice that the argument is passed to the derived class’s constructor in the normal
fashion.

4.2.4 Multiple Inheritance


There are two ways that a derived class can inherit more than one base class.
First, a derived class can be used as a base class for another derived class, creating

Page 94
Object Oriented Programming

multilevel class hierarchy. In this case, the original base class is said to be an indirect
base class of the second derived class. (keep in mind that any class-no matter how it is
created –can be used as a base class.)second, a derived class can directly inherit more
than one class. in this situation, two or more base classes are combined to help create the
derived class. there are several issues that arise when multiple base classes are involved,
and
These issues are examining in this section.

When a base class is used to derive a class that is used as a based class for another
derive class, the constructor functions of all three classes are called in order of derivation.
(this is a generalization of the principle you learned earlier in this chapter.)also,destructor
function of called in reverse order.thus, if class b1 is inherited by d1,and d1 is inherited
by d2,b1’s constructor is called first, followed by d1’s, followed by d2’s.the destructor
are called in reverse order. When derived class directly inherits multiple base classes, it
uses this expanded declaration:

Class derived-class-name: access base1,access base2,…..,access baseN


{
//…body of class
}
here base1 through base N are the base class names and access is the access
specifier, which can be different for each base class. when multiple base classes are
inherited, constructors are executed in the order, left to right ,that the base classes are
specified. Destructors are executed in the opposite order.
When class inherits multiple base classes that have constructors that require
arguments, the derived class passes the necessary arguments to them by using this
expanded form of the derived class constructor function:

Derived-constructor(arg-list):base1(arg-list),base2(arg-list),….,baseN(arg-list)
{
//body of derived class constructor
}
here base1 through base N are the names of the base classes.

When a derived class inherits a hierarchy of classes, each derived class in the
chain must pass back to its preceding base any arguments it needs.

EXAMPLES:
Annamalai University
1. Here is an example of a derived class that inherits a class derived from another
class. notice how arguments are passed along the chain from D2 to B1.

//multiple inheritance
#include <iostream.h>
using namespaces std;
class b1{
int a;

Page 95
Object Oriented Programming

public:
b1(int x){a=x;}
int geta() {return a;}
};
// inherit direct space class
class d1:public b1{
int b;
public:
d1(int x,int y):b1(y)//pass y to b1
{
b=x;
}
int getb() {return b;}
};
// inherit a derived class and an indirect base.
Class d2:public d1 {
Int c;
Public:
D2(int x,int y,int z):d1(y,z) //pass args to d1
{
c=x;
}
/* because bases inherited as public,d2 has access to public elements of both b1 and d1.*/
void show()
{
cout<<geta () <<’ ‘<<getb() <<’ ‘;
cout <<c<<’\n’;
}
};
int main()
{
d2 ob(1,2,3);
ob.show();
//geta()and getb() are still public here cout<<ob.geta()<<’ ‘<<ob.getb()<<’\n’;
return 0;
}
Annamalai University
the call to ob.show () displays 3 2 1. in this example, B1 is an indirect base class
of D2.notice that D2 has access to the public members of both D1and B1.as you should
remember, when public members of a base class are inherited as public, they become
public members of the derived class. Therefore, when D1 inherits B1, geta() becomes a
public members of D1, which becomes members of D2.

As the program illustrates, each class in a class hierarchy must pass all arguments
required by each preceding base class. Failure to do so will generate a compile-time error.
The class hierarchy created in this program is illustrated here:

Page 96
Object Oriented Programming

D2->D1->B1
Before we move on, a short discussion about how to draw C++ -style inheritance
graphs is in order. In the preceding graph, notice that the arrows point up instead of
down. traditionally++ programmers usually draw inheritance charts as directed graphs in
which the arrow points from the derived class to the base class. While newcomers
sometimes fine this approach counter-intuitive, it is nevertheless the way inheritance
charts are usually depicted in C++.

2. Here is a reworked version of the preceding program, in which a derived class


directly inherit two base classes:

#include <iostream.h>
using namespace std;
//create first base class.
Class B1
{
int a;
public:
B1(int x)
{
a=x;
}
int geta(){ return a;}
};
// create second base class.
Class B2{
int b;
Public:
B2(int x)
{
b=x;
}
int getb(){return b;}
};
// directly inherit two base classes.
Class d: public B1,public B2 {
int c;
Public:
Annamalai University
// here z and y are passed directly to B1 and B2
D(int x, int y,int z) : B1(z),B2(y)
{
c=x;
}
/* Because bases inherited as public has access to public element of both B1 and B2 .*/
void show(){
cout<<geta()<<’ ‘<<getb()<<’ ‘;

Page 97
Object Oriented Programming

cout<<c<<’\n’;
}
};
int main()
{
D ob(1, 2, 3);
Ob.show();
return 0;
}
in this version, the arguments to B1 and B2 are passed individually to these classes by
D. This program creates a class that looks like this:

B1 B2

4.2.5 Virtual Base Classes


A potential problem exists when multiple base classes are directly Inherited by a
derived class. To understand what this problem is, consider the following class hierarchy:
Base Base

Derived 1 Derived2

Derived3

Here the base class Base is inherited by both Derived1 and Derived2. Derived 3
directly inherits both Derived1 And Derived2. however, this implies that base is actually
inherited twice by Derived 3-first it is inherited through Derived1, and then again through
Annamalai University
Deriverd2. This causes ambiguity when a member of base is used by Derived3. Since two
copies of base are included in Derived3,is a reference to a member of base referring to
the base inherited indirectly through Derived1 or to the Base inherited indirectly through
Derived2? To resolve this ambiguity, C++ includes a mechanism by which only one copy
of base will be included in Derived3.This feature is called a virtual base class.

In situations like the one just described, in which a Derived class indirectly
inherits the same base class more than once, it is possible to prevent two of the base from
being present in the Derived object by having the base class inherited as virtual by any
Derived classes. Doing this prevents two (or more) copies of the base from being

Page 98
Object Oriented Programming

presenting any subsequent Derived class that inherits the base class indirectly. The
virtual keyword precedes the base class access specifier when it is inherited by a derived
class.

EXAMPLES:

1. Here is an example that uses a virtual base class to prevent two copies of base
from begin present in derived3.

// This program uses a virtual base class.


#include <iostream.h>
using namespace std;
class base {
public:
int i;
};
// Inherit base as virtual.
class derived1 : virtual public base {
public:
int j;
};

// Inherit base as virtual here, too.


class derived2 : virtual public base {
public :
int k;
};

/* Here, derived3 inherits both derived1 and derived2. However, only one copy of base is
present.
*/

class derived3 : public derived1 , public derived2 {


public :
int product( ) { return i* j * k ; }
};

int main( )
Annamalai University
{
derived3 ob;

ob.i = 10; // unambiguous because only one copy present


ob.j = 3;
ob.k = 5;

cout << “Product is “ << ob.product( ) << “\n”;

Page 99
Object Oriented Programming

return 0;
}

If derived1 and derived2has not inherited base as virtual, the statement

Ob.i = 10;

4.2.6 Some C++ I/O Basic


Before we begin our examination of C++ I/O, a few general comments are in
order. The C++ I/O system, like the C I/O system, operates through streams. Because of
your C programming experience, you should already know what a stream is, but here is a
summary. A stream is a logical device that either produces or consumes information. A
stream is linked to a physical device by the C++ I/O system. All streams behave in the
same manner even if the actual physical device they are linked to differ. Because all
streams act the same, the I/O system presents the programmer with a consistent interface,
even though it operates on device with differing capability. For example, the same
function that you use to write to the screen can be used to write to a disk file or to the
printer.

As you know, when a C programmer begin execution, three predefined streams


are automatically opened: stdin , stdout , and stderr. A similar thinks happens when a
C++ program starts running. When a C++ program begins these four streams are
automatically opened:

Stream Meaning Default Device


cin Standard input Keyboard
cout Standard output Screen
cerr Standard error Screen
clog Buffered version of cerr Screen

As you have probably guessed, the streams cin , cout , and cerr corresponding to
C’s stdin , stdout , and stderr . You have already been using cin and cout. The stream
clog is simply a buffered version of cerr. The standard C++ also opens wide (16-bit)
character version of these streams called wcin, wcout , and wclog, but we won’t be
using them in this book. The wide character streams exit to support languages, such as
Annamalai University
Chinese, that require large character sets.

By default, the standard stream are used to communicate with the console.
However, in environments that support I/O redirection, these stream can be redirected to
other devices.

As you have seen earlier, C++ provides support for its I/O system in the header
file <iostream.h>. In this file, a rather complicated set of class hierarchies is defined that
supports I/O operations. The I/O classes begin with a system of template classes.

Page 100
Object Oriented Programming

Template classes, also called generic classes, will be discussed earlier. Briefly, a
template class defines the form of a class without fully specifying the data upon which it
will operate. once a template class has been defined, specific instance of it can be created.
As it relate to the I/O library, Standard C++ creates two specific versions of the I/O
template class: one for 8-bit characters and another for wide characters. This book will
discuss only the 8-bit character classes, Since they are by far the most frequently used.

The C++ I/O system is built upon two related, but different, template class
hierarchies. The first is derived from the low-level I/O class called basic_streambuf.
This class supplies the basic, low-level input and output operations and provides the
underlying support for programming, You will not need to use basic_streambuf
Directly. The class hierarchy that you will most commonly be working with is derived
from basic_ios. This highlevel I/O class that provides formatting, error-checking, and
status information related to stream I/O. basic_ios is used as a base for several derived
classes, including basic_istream, basic_ostream , and basic_iostream. These classes
are used to create streams capable of input, output, and input/output respectively.

As explained earlier, the I/O library creates to specific versions of the class
hierarchies just described: one for 8-bit characters and one for wide characters. The
following table shows the mapping of the template class names to the 8-bit character-
based versions.

Template Class 8-bit Character-Based Class


basic_streambuf streambuf
basic_ios ios
basic_istream istream
basic_ostream ostream
basic_iostream iostream
basic_fstream fstream
basic_ifstream ifstream
basic_ofstream ofstream

The character-based names will be used through out the remainder of this book,
Since they are the names that you will use in your programes. They are also the same
names that were used by the old I/O library. This is why the old and the new I/O library
are compatible at the source code level.
Annamalai University
One last point: The ios class contains many member functions and variables that
control or monitor the fundamental operation of a stream. It will be referred to frequently.
Just remember that if you include <iostream.h> in your program, you will have access to
this important class

4.2.7 Formatted I/O

Until now, all examples in this book displayed information to the stream using
C++’s default formats. However, it is possible to output information in a wide variety of

Page 101
Object Oriented Programming

forms. In fact, you can format data using C++’s I/O system in much the same way that
you do using C’s printf ( ) function. Also, you can alter certain aspects of the way
information is input.
Each stream, has associated with it a set of format flags that control the way
information is formatted. The is class declared a bitmask enumeration called fmtflags, in
which the following values are defined:

adjustfield floatfield right skipws


basefield hex scientific unitbuf
boolalpha internal showbase uppercase
dec left showpoint
fixed oct showpos

These value are used to set or clear the format flags and are defined within ios. If
you are using and older, nonstandard compiler, it may not defined fmtflags enumeration
type. In this case, the format flags will be encoded into long integer.

When the skipws flag is set, leading white space characters(spaces, tabs and
newlines) are discarded when input is being performed on a stream. When skipws is
cleared, white space character are not discarded.

When the left flag is set, output is left justified. When right is set, output is right
justified. When the internal flags is set, a numeric value is padded to fill a field by
inserting spaces between any sign or base character. If none of these flags is set, output is
right justified by default.

By default, numeric value are output in decimal. However, it is possible top


change the number base. Setting the oct flags causes output to be displayed in octal.
Setting the hex flag causes output to be displayed in hexadecimal. To return output to
decimal, set the dec flag.

Setting showbase because the base of numeric value to be shown. For example,
if the conversion base hexadecimal, the value 1F will be displayed as 0*1F.

By default, when scientific notation is displayed the e is lowercase. When the


uppercase is set, these character are displayed uppercase. Setting showpos causes a
Annamalai University
leading plus sign to be displayed before positive value. Setting showpoint causes a
decimal point and trailing zeros to be displayed floating-point output-whether needed or
not.

If the scientific flag is set, floating-point numeric values are displayed using
scientific notation. When fixed is set, floating-point values are displayed using normal
notation. When neither flag is set, the compiler chooses an appropriate method. When the
unitbuf is set, the buffer is flushed at each insertion operation. When boolalpha is set,
Booleans can be input or outputs using the keywords true and false.

Page 102
Object Oriented Programming

Since it is common to refer to the oct, dec and hex fields, they can be
collectively referred to as basefield. Similarly, the left, right, and internal fields can be
referred to as adjustfield. Finally, the scientific and fixed fields can be referenced as
floatfield.

To set a format flag, use the setf ( ) function. this function is a member of ios. its
most common form is shown here :

Fmtflags setf(fmtflags flags);


This function returns the previous settings of the format flags specified by
flags.(all other flags are unaffected .)

For example, to turn on the showpos flag, you can use this statement:
String.setf(ios::showpos);

Here stream is the stream you wish to affect. Notice the use of the scope
resolution operator. Remember, showpos is an enumerated constant within the ios class.
Therefore, it is necessary to tell the compiler this fact by preceding showpos with the
class name and the scope resolution operator. If you don’t, the constant showpos will
simply not be recognized.

It is important to understand that setf( ) is a member function of the ios class


and affects streams created by that class. Therefore, any of call to setf( ) is done relative
to a specific stream. There is no concept of calling setf( ) by itself. Put differently. There
is no concept in C++ of global format status. Each stream maintains its own format status
information individually.

It is possible to set more than one flag in a single call to setf( ), rather than
making multiple calls. To do this, OR together the values of the flags you want to set. For
example, this call sets the showbase and hex flags for cout:

cout.setf(ios::showbase | ios::hex);

4.2.8 Using Width( ), Precision( ), And Fill( )


In addition to the formatting flags, there are three member functions defined by
ios that set these format parameters: the field width, the precision, and the fill character.
Annamalai University
These are width( ), precision( ) and fill( ), respectively.
By default, when a value is output, it occupies only as much space as the number
of characters it takes to display it. However, you can specify a minimum field width by
using the width( ) function. Its prototype is shown here:

streamsize width(streamsize w);

Here w becomes the field width, and the previous field width is returned. The
streamsize type is defined by <iostream> as some form if integer. In some
implementations, each time an output operation is performed, the field width returns to its

Page 103
Object Oriented Programming

default setting, so it might be necessary to set the minimum field width before each
output statement.
After you set a minimum field is padded with the current fill character (the space,
by default) so that the field width is reached. However, keep in mind that if the size of the
output value exceeds the minimum field width, the field will be overrun. No values are
truncated.
By default, six digits of precision are used. You can set this number by using the
precision( ) function. Its prototype is shown here:
streamsize precision(streamsize p);
Here the precision is set to p and the old value is returned.

By default, when a field needs to be filled, it is filled with spaces.


You can specify the fill character by using the fill( ) function. Its prototype is shown here:

char fill(char ch);

After a call to fill( ), ch becomes the new fill character, and the old one is returned.

EXAMPLES
1. Here is a program that illustrates the format functions:

#include<iostream.h>
using namespace std;
int main( )
{
cout.width(10); //set minimum field width
cout<< “hello” <<’\n’; //right-justify by default
cout.fill(‘%’); //set fill character
cout.width(10); //set width
cout<< “hello” <<’\n’; //right-justify by default
cout.setf(ios::left); // left-justify
cout.width(10); //set width
cout<< “hello” <<’\n’; //output left justified
cout.width(10); //set width
cout.precision(10); //set 10 digits of precision
cout <<123.234567<< ‘\n’;
cout.width(10);
cout.precision(6);
Annamalai University
//set width
//set 6 digits of precision
cout <<123.234567<< ‘\n’;

return 0;
}

This program displays the following output:

Page 104
Object Oriented Programming

hello
%%%%%hello
hello%%%%%
123.234567
123.235%%%

Notice that the field width is set before output statement.

2. The following program shows how to use the C++ I/O format functions to create an
aligned table of numbers:

//Create a table square roots and squares.


#include<iostream.h>
#include<cmath.h>
using namespace std;
int main( )
{
double x;
cout.precision(4);
cout << “ x sqrt(x) x^2\n\n”;
for(x=2.0;x<=20.0;x++) {
cout.width(7);
cout <<x <<” “;
cout.width(7);
cout<<sqrt(x)<<” “;
cout.width(7);
cout<<x*x<<’\n’;
}
return 0;
}

This program creates the following table:

X sqrt(x) x^2

2 1.414 4
3
4
1.732
2
Annamalai University
9
16
5 2.236 25
6 2.449 36
7 2.646 49
8 2.828 64
9 3 81
10 3.162 100
11 3.317 121
12 3.464 144

Page 105
Object Oriented Programming

13 3.606 169
14 3.742 196
15 3.873 225
16 4 256
17 4.123 289.
18 4.243 324
19 4.359 361
20 4.472 400

4.2.9 Using I/O Manipulators


There is a second way that you can format information using C++’s I/O system.
This method uses special functions called I/O manipulators. As you will see, I/O
manipulators are, in some situations, easier to use than the ios format flags and functions

I/O manipulations are special I/O format functions that can occur within an I/O
statement, instead of separate from it the way the ios member functions must. The
standard manipulations are shown below. As you can see, many of the I/O manipulators
parallel member functions of the ios class. Many of the manipulators shown were added
recently to standard C++ and will be supported only by modern compilers.

To access manipulators that take parameters, such as setw( ), you must


include<iomanip> in your program. This is not necessary when you are using a
manipulator that does not require an argument.

As stated above, the manipulators can occur in the chain of I/O operations. For
example:

cout << oct<< 100 <<hex <<100;


cout <<setw(10) <<100;

The first statement tells cout to display integers in octal and then outputs 100 in octal. It
then tells the stream to display integers in hexadecimal and then outputs 100 in
hexadecimal format. The second
________________________________________________________________________
_
Manipulator Purpose
Input/Output Annamalai University
boolalpha Turns on boolalpha flag Input/Output
dec Turns on dec flag Input/Output
endl Outputs a newline character and flushes the stream Output
ends Outputs a null Output
fixed Turns on fixed flag Output
flush Flushes a stream Output
hex Turns on hex flag Input/Output
internal Turns on internal flag Output

Page 106
Object Oriented Programming

left Turns on left flag Output


noboolalpha Turns off boolalpha flag Input/Output
noshowbase Turns off showbase flag Output
noshowpoint Turns off showpoint flag Output
noshowpos Turns off showpos flag Output
noskipws Turns off skipws flag Input
nounitbuf Turns off unitbuf flag Output
nouppercase Turns off uppercase flag Output
oct Turns on oct flag Input/Output
resetiosflags(fmtflags f) Turns off the flags specified in f
right Turns on right flag Output
scientific Turns on scientific flag Output
setbase(int base) Sets the number base to base Input/Output
setfill(int ch) Sets the fill character to ch Output
setiosflags(fmtflags f) Turns on the flags specified in f
setprecision(int p) Sets the number of digits of precision Output
setw(int w) Sets the field width to w Output
showbase Turns on showbase flag Output
showpoint Turns on showpoint flag Output
showpos Turns on showpos flag Output
skipws Turns on skipws flag Input
unitbuf Turns on unitbuf flag Output
uppercase Turns on uppercase flag Output
ws Skips leading white space Input

statement sets the field width to 10 and then displays 100 in hexadecimal format again.
Notice that when a manipulator does not take an argument, such as oct in the example, it
is not followed by parentheses. This is because it is the address of the manipulator that is
passed to the overloaded << operator.

Keep in mind that an I/O manipulator affects only the stream of which the I/O
expression is a part. I/O manipulators do not affect all streams currently opened for use.

As the preceding example suggests, the main advantage of using manipulators


over the ios member functions is that they are often easier to use and allow more compact
code to be written.
Annamalai University
If you wish to set specific format flags manually by using a manipulator, use
setiosflags( ). This manipulator performs the same function as the member function setf(
).
To turn off flags, use the resetioflags( ) manipulator. This manipulator is equivalent to
unsetf( )

Page 107
Object Oriented Programming

4.2.10 Creating your own inserters


As stated earlier one of the advantages of the c++ i/o system is that you can
overload the i/o operators for classes that you create .by doing so you can seamlessly
incorporate your classes into your c++ programs. In this section you can learn how to
overload c++’s output operator<<.

In this language of c++, the output operation is called an insertion and the <<is
called the insertion operator. when you overload the <<for output ,you are creating an
inserter function or inserter for short. The rationale for these terms comes from the fact
that an output operator inserts information into stream.

All inserter function have this general form:


Ostream&operator<<(ostream &stream,class-name ob)
{
//body of inserter
return stream;
}
the first parameter is a reference to an object of type ostream. this means that stream
must be an output stream. The second parameter receives the object that will be output.
Notice that the inserter function returns a reference to stream, which is of type ostream.
this is required if the overloaded<< is going to be used in a serious of i/o expression such
as
cout<<ob1<<ob2<<ob3;

Within a n inserter you can perform any type of procedure. What an inserter does
is completely up to you. However, for the inserter to be consistent with good
programming practices, you should limit its operations to output ting the information to a
stream.

Although you might find this surprising at first, an inserter cannot be a member of
the class on which it is designed to operate. Here is why: when an operator function of
any type is the member of the class ,the left operand, which is passed implicitly through
the this pointer, is the object that generates the call to the operator function. This implies
Annamalai University
that the left operand is an object of that class. Therefore, if an overloaded operator
function is a member of a class, the left operand must be an object of that class.
However,when you create an inserter, the left operand is a stream and the right operand is
the object that you want to output. Therefore, an inserter cannot be a member function.

The fact that an inserter cannot be a member function might appear to be a serious
flaw in c++ because it seems to imply that all data of a class that will be output using an
inserter will need to be public, thus violating the key principle of encapsulation.
However, this is not the case. Even though inserters cannot be members of the class upon
which they are designed to operate, they can be friends of the class. In fact, in most

Page 108
Object Oriented Programming

programming situations you will encounter, an overloaded inserter will be a friend of the
class for which it was created.

EXAMPLES:
1. As a simple first example, this program contains an inserter for the coord class,
developed in a previous chapter:

//Use a friend inserter for objects of type coord.


#include <iostream.h>
using namespace std;
class coord{
int x,y;
public:
coord ( ) {x=0;y=0}
coord(int i,int j){x = I ;y = j ;}
friend ostream &operator<<(ostream &stream,coord ob);
};
ostream &operator<<(ostream &stream, coord ob)
{
stream<<ob.x<<”,”<<ob.y<<’\n’;
return stream;
}
int main()
{
coord a(1,1),b(10,23);
cout<<a<<b;
return 0;
}
This program displays the following:
1 ,1
10,23

The inserter in this program illustrates one very important point about creating
your own inserter:make them as general as possible. In this case, the I/O statement inside
the inserter outputs the values of x and y to stream, which is whatever stream is passed
to the function. As you will see in the following chapter. when written correctly the same
Annamalai University
inserter that outputs to the screen can be used to output to any stream .Sometimes
beginners are temped to write the coord inserter like this:

Ostream&operator<<(ostream&stream, coord ob)


{
cout<<ob.x<<”,”<<ob.y<<’\n’;
return stream;
}

Page 109
Object Oriented Programming

In this case, the output statement is hard-coded to display information on the


standard output device linked to cout. However ,this prevents the inserter from being
used by other streams. The point is that you should make your inserters as general as
possible because there is no disadvantage to doing so.

4.2.11 Creating Extractors


Just as you can overload the << output operator, you can overload the >>input
operator. In c++, the >> is referred to as the extraction operator and a function that
overloads it is called an extractor. The reason for this term is that the act of inputting
information from a stream removes (that is, extracts) data from it.

The general form of an extractor function is shown here:


Istream&operator>>(istream&stream,class-name&ob)
{
//body of extractor
return stream;
}
Extractors return a reference to istream, which is an input stream. The first
parameter must be a references to an input stream. The second parameter is a reference to
the object that is receiving input.
For the same reason that an inserter cannot be a member function, an extractor
cannot be a member function. Although you can perform any operation within an
extractor, it is best to limit its activity to inputting information.

EXAMPLES:

1.This program adds an extractor to the coord class:

//Add a friend extractor for objects of type coord.


#include<iostream.h>
using namespace std;

class coord{
int x,y;
public:
coord() { x=0;y=0;}
Annamalai University
coord(int i,int j) {x=icy=j;}
friend ostream&operator<<(ostream&stream,coord ob);
friend istream&operator>>(istream&stream,coord &ob);
};
ostream&operator<<(ostream&stream,coord ob)
{
stream<<ob.x<<”,”<<ob.y<<’/n’;
return stream;
}
istream&operator>>(istream&stream,coord&ob)

Page 110
Object Oriented Programming

{
cout <<”enter coordinates:”;
stream>>ob.x>>ob.y;
return stream;
}
int main()
{
coord a(1, 1),b(10, 23);
cout <<a <<b;

cin >>a;
cout <<a;

return 0;
}
Notice how the extractor also prompts the user for input.
Although such prompting is not required(or even desired)for most situations, this
function shows how a customized extractor can simplify coding when a prompting
message is needed.

2. Here an inventory class is created that stores the name of a item, the number on hand,
and its cost. The program includes both an inserter and a extractor for this class.

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

class inventory{
char item[40]; //name of item
int onhand; //number on hand
double cost; //cost of item
public:
inventory(char*I,int o,double c)
{
strcpy(item, I);
onhand=0;

}
Annamalai University
cost = c;

friend ostream &operator<<(ostream &stream,inventory ob);


friend istream&operator>>(istream&stream,inventory&ob);
};
ostream&operator <<(ostream&stream,inventory ob)
{
stream<<ob.item<<”:”<<ob.onhand;
stream<<”on hand at $”<<ob.cost<<’\n’;

Page 111
Object Oriented Programming

return stream;
}
istream&operator>>(istream&stream,inventory&ob)
{
cout<<”enter item name:”;
stream>>ob.item;
cout<<”enter number on hand:”;
stream>>ob.onhand;
cout<<”enter cost:”;
stream>>ob.cost;

return stream;
}
int main()
{
inventory ob(“hammer”, 4, 12.55);
cout<<ob;
cin>>ob;
cout<<ob;
return 0;
}

4.3) Revision Points

BASE CLASS: A class from which other classes are derived.

PROTECTED MEMBER: A protected member is the same as a private member


except that a protected member of a base class is inherited by a derived class.

CONSTRUCTOR: A special member functions for automatically creating an


instance of a class. It has the same name as the class.

DESTRUCTOR: A function that is called to de-allocate memory of the objects of a


class.
Annamalai University
INHERITANCE: Inheritance is the process by which one object can acquire the
properties of another object.

MULTIPLE INHERITANCES: Multiple inheritances are the process of creating a


new class from more than one base class.

VIRTUAL BASE CLASSES: A base class that has been qualified as virtual in the
inheritance definition. Only one copy of its members will be inherited regardless of
the number of inheritance paths between the base and derived class.

Page 112
Object Oriented Programming

I/O MANIPULATORS: Functions that when ‘output’ or ‘input’ cause no I/O, but
set various conversion flags or parameters.

EXTRACTOR: The >> is referred to as the extraction operator and a function that
overloads it is called an extractor.

WIDTH ( ): To specify the require field size for displaying an output value.

PRECISION (): To specify the number of digits to be displayed after the decimal
point of a float value.

4.4) Intext Questions


1) What is class inheritance?
2) Give the merits and demerits of inheritance.
3) What is significance of ‘protected’ data members and member functions in
Inheritance?
4) What are Virtual base functions?
5) Illustrate the use of Manipulators. Give two e.g.
6) Give the syntax for creating user defined Manipulators
7) What is an Extractor?
8) List out the C++ I/O basics.
9) What is the use of width () and Precision ( )?
10) What are multiple inheritances?
11) Distinguish between Constructor and Destructor.

4.5) Summary

 A new class that is created from an existing class using the principle of
inheritance is called a Derived class or Sub class.
 The parent class is called the base class.
 A class intended to a base class usually should use protected instead of private
members.
 Inheritance is the process by which one object can acquire the properties of
another object.
 Annamalai University
Inheritance allows the new classes to be built from older and less specialized
classes instead of being rewritten from scratch. The technique of building new
classes from the existing class is called inheritance.
 Multiple inheritances are the process of creating a new class from more than one
base class.
 Multiple inheritances are a derived class declared to inherit properties of two or
more parent classes.
 You can specify a minimum field width by using the width ( ) function.
 Precision () is to specify the number of digit to be displayed after the decimal
point of a float value.
 Fill ( ) is to specify a character that is used to fill the unused portion of a field.

Page 113
Object Oriented Programming

 The output operation is called an insertion and << is called the insertion operator.
 Even though inserters cannot be member of the class upon which they are
designed to operate, they can be friend of a class.
 If an overloaded operator function is a member of a class, the left operand must be
an object of that class.
 When you create an inserter, the left operant is a stream and the right operand is
the object that you want to output.
 When a base class and a derived class both have constructor and destructor
functions, the constructor functions are executed in order of derivation.

4.6) Terminal Exercises

1) If the specifier is not present, it is __________ by default if the derived class is a


‘class’.
2) If the derived class is a struct, ____________ is the default in the absence of an
explicit access specifier.
3) The _______ access specifier is equivalent to the private specifier with the sole
exception.
4) A base class can also be inherited as _________ by derived class.
5) Is it possible for the derived class to ignore all arguments and pass them along to
the base? TRUE/FALSE.
6) Is the derived class’s destructor is executed before the base class’s destructor.
TRUE/FALSE.
7) ____________ Inheritance is a derived class declared to inherit properties of two
or more parent classes.
8) Multiple inheritances can combine the behaviour of multiple base classes in a
single derived class. TRUE/FALSE.
9) _______ to specify the number of digits to be displayed after the decimal point
of a float value.
10) __________ to specify a character that is used to fill the unused portion of a field.

4.7) Supplementary Materials

12. Teach yourself C++, third edition, HERBERT SCHILDT, Tata Mc Graw Hill

Annamalai University
13. Practical C++ Programming By Steve Oualline

4.8) Assignments

1) Write an assignment on multiple inheritances?


2) Write a note on I/O Manipulators.
3) Write an assignment on constructor and destructor.

4.9) Reference Books


14. For Game Programmers (Game Development Series) by Noel Llopis

Page 114
Object Oriented Programming

15. The C++ Standard Library: a tutorial and reference By Nicholai M.


Josuttis

4.10) Learning Activities


1. Design a class ‘Employee’ of an organization with members Employee_no,
Name, Designation, Basic pay. Define a derived class ‘Executive’ whose
Basic_pay is more than Rs.10, 000.
2. A private member of a base class is inheritable. Is there any way for the objects of
a derived class without modifying the class? Justify your answer?
3. Design manipulator and the corresponding C++ code to provide the following
output specifications:
 Take a,b,c float values from the keyboard input.
 Compute the value (-b+ (b**2-4*a*c))/2*a.
 Repeat the above for 10 times.

4.11) Keywords
Base class – A class from which other classes are derived.
Inheritance – Inheritance is a process by which one object can acquire the properties
of another object.
Protected Member - Protected member of a base class is inherited by a derived class.
Multiple Inheritance – This allows a derived class to have more than one base class.
Manipulator – A data object that is used with the insertion and extraction operators.

Annamalai University

Page 115
Object Oriented Programming

UNIT-V

5.0) Introduction
This chapter gives an overall view about the important concepts of C++. In
addition to overloading, you can further customize C++’s I/O system by creating own
manipulator functions. C++ supports all of ‘C’s rich set of I/O functions. We can use any
of them in the C++ programs.
Object oriented programming language support polymorphism. In C++,
polymorphism means the ability to take more than one form. The I/O systems of C++
handle file operations, which are very much similar to the console input and output
operations. Also C++ provides a built-in error handling mechanism that is called
exception handling.

5.1) Objectives

In the chapter the read will be able learn manipulators and the methods used for
creating user define manipulators. The concept of creating files have also been discussed
in this chapter. We will also learn about the different Input Output functions used for
creating files.

5.2) Content
5.2.1 Creating Your Own Manipulators
In addition to overloading insertion and extraction operators, you can further
customize c++’s I/O system by creating your own manipulator functions. Custom
manipulators are important for two main reasons. First, an manipulator consolidate a
sequence of several separate I/O operations. For example, it is not uncommon to have
situations in which the same sequence of I/O operations occurs frequently within a
program. in these cases you can use a custom manipulator to perform these actions, thus
simplifying your source code and preventing accidental error. Second, a custom
manipulator can be important when you need to perform I/O operations on a nonstandard
device.

Annamalai University
For example, you could use a manipulator to send control codes to a special type
of printer or an optical recognition system.

Custom manipulators are a feature of c++ that supports oop, but they can also
benefit programs that aren’t object oriented. As you will see ,custom manipulator can
help any I/O intensive program clearer and more efficient.

As you know, there are two basic types of manipulators:those that operate on
input streams and those that operate on output streams. In addition to these two broad
categories ,there is a secondary division:those manipulators that they can argument and

Page 116
Object Oriented Programming

those that don’t . There are some significant differences between the way a parameterless
manipulator and a parameterized manipulators are created. Further creating
parameterized manipulators is substantially more difficult than creating parameterless
ones and is beyond the scope of this book. However, writing your own parameterless
manipulators is quite easy and is examined here.

All parameterless manipulators output functions have this skeleton:

ostream &manip-name(ostream &stream)


{
//your code here
return stream;
}

Here manip-name is the name of the manipulator and the stream is a reference to
the invoking stream. A reference to the stream is returned. This is necessary if a
manipulator is used as a part of a larger I/O expression. It is important to understand that
even though the manipulator has as its single argument a reference to the stream upon
which it is operating, no argument is used when the manipulator is called in a output
operation.
All parameterless input manipulator functions have this skeleton:

istream &manip-name(istream &stream)


{
//your code here
return stream;
}

An input manipulator receives a reference to the stream on which it was invoked.


This stream must be return by the manipulator.

REMEMBER:

It is crucial that your manipulators return a reference to the invoking stream. If this is not
done, your manipulators cannot be used in a sequence of input or output operations.

EXAMPLE: Annamalai University


1. As a simple first example, the following program creates a manipulator called setup( )
that sets the field width to 10, the precision to 4, and the fill character to *.

#include<iostream>
using namespace std;

ostream &setup(ostream &stream)


{
stream.width(10);

Page 117
Object Oriented Programming

stream.precision(4);
stream.fill(‘*’);

return stream;
}

int main( )
{
cout<< setup<<123.123456;
return 0;
}

As you can see,setup is used as part of an I/O expression in the same way that any
of the built-in manipulators would be used.

5.2.2 File I/O Basics


It is now time to turn our attention to the file I/O. As mentioned in the preceding
chapter, file I/O and console I/O are closely related. In fact, The same class hierarchy that
support console I/O also support file I/O. Thus, most of what you have already learned
about I/O applies to files as well. Ofcourse, file handling makes use of several new
features.

To perform file I/O, you must include the header <fstream> in your program. It
defines several classes, including ifstream, ofstream and fstream. These classes are
derived from istream and ostream. Remember, istream and ostream are derived from
ios, so ifstream, ofstream and fstream also have access to all operations defined by
ios(discussed in the preceding chapter).

In C++, a file is opened by linking it to a stream. There are three types of streams:
input, output and input/output. Before you can open a file, you must first obtain a stream.
To create an input stream, declare an object of type ifstream. To create an output stream
declare an object of type ofstream. Streams that will be performing both input and output
operations must be declared as objects of type fstream. For example, This fragment
creates one input stream, one output stream , and one stream capable of both input and
output:
Annamalai University
ifstream in; //input
ofstream out; //output
fstream ion; //input and output

Once you have created a stream, one way to associate it with a file is by using the
function open( ). This function is a member of each of the three file stream classes. The
prototype for each is shown here:

Void ifstream::open(const char *filename,

Page 118
Object Oriented Programming

Openmode mode=ios::in);
Void ofstream::open(const char *filename,
Openmode mode=ios::out | ios::trunc);
Void fstream::open(const char *filename,
Openmode mode=ios::in | ios::out);

Here filename is the name of the file, which can include a path specifier. The
value of mode determines how the file is opened. It must be a value of type openmode,
which is an enumeration defined by ios that contains the following values:

Ios::app
Ios::ate
Ios::binary
Ios::in
Ios::out
Ios::trunc

You can combine two or more of these values by oring them together. Let’s see
what each of these values means.

Including ios::app causes all output to that file to be appended to the end. This
value can be used only with files capable of output. Including ios::ate causes a seek to
the end of the file to occur when the file is opened. Although ios::ate causes a seek to
end-of-file, I/O operations can still occur anywhere within the file.

The ios::in value specifies that the file is capable of input. The ios::out values
specifies that the file is capable of output.

The ios::binary values causes a file to be opened in binary mode. By default, all
files are opened in text mode. In text mode, various character translations might take
place, such a carriage return/linefeed sequences being converted into newlines. However,
when a file is opened in a binary mode, no such character translation will occur. Keep in
mind that any file, whether it contains formatted text or raw data, can be opened in either
binary or text mode. The only difference is whether character translations take place.

The ios::trunc value causes the contents of a preexisting file by the same name to
Annamalai University
be destroyed and the file to be truncated to zero length. When you create an output stream
using ofstream, any preexisting file with the same name is automatically truncated.

The following fragments opens an output file called test:

ofstream mystream;
mystream.open(“test”);

Since the mode parameter to open( ) defaults to a value appropriate to the type of
stream being opened, there is no need to specify its value in the preceding example.

Page 119
Object Oriented Programming

If open( ) fails, the stream will evaluate to false when used in the Boolean
expression. You can make use of this fact to confirm that the open operation succeeded
by using a statement like this:

if (!mystream) {
cout<< “Cannot open file.\n”;
// Handle error
}

In general, you should always check the result of a call to open( ) before
attempting to access the file. You can also check to see if you have successfully opened a
file by using the is_open( ) function, which is the member of fstream, ifstream, and
ofstream. It has this prototype.

bool is_open( );

It returns true if the stream is linked to an open file and false otherwise. For
example, the following checks if mystream is currently open:

if(!mystream.is_open( )) {
cout<< “File is not open.\n”;
// ...

Although it is entirely proper to open a file by using the open( ) function, most of
the time you will not do so because the ifstream, ofstream, and fstream classes have
constructor functions have the same parameters and defaults as the open( ) function.
Therefore, the most common way you will see a file opened is shown in this example:

ifstream mystream(“myfile”); // Open file for input

As stated, if for some reason the file cannot be opened, the stream variable will
evaluate as false when used in a conditional statement. Therefore, whether you use a
constructor function to open the file or an explicit call to open( ), you will want to
confirm that the file has actually been opened by testing the value of the stream.

Annamalai University
To close a file, use the member function close( ). For example, to close the file
linked to a stream called mystream, use this statement:

mystream.close( );

The close( ) function takes no parameters and returns no value. You can detect
when the end of an input file has been reached by using the eof( ) member function of
ios. It has this prototype:

bool eof( )

Page 120
Object Oriented Programming

It returns true when the end of the file has been encountered and false otherwise.

Once a file has been opened, it is very easy to read textual data from it or write
formatted, textual data to it. Simply use the << and >> operators the same way you do
when performing console I/O, except that instead of using cin and cout, substitute a
stream that is linked to a file. In a way, reading and writing files by using >> and << is
like using C’s fprintf( ) and fscanf( ) functions. All information is stored in the file in the
same format it would be in if displayed on the screen. Therefore, a file produced by using
<< is a formatted text file, and any file read by >> must be a formatted text file.
Typically, files that contain formatted text that you operate on using the >> and <<
operators should be opened for text rather than binary mode. Binary mode is best used on
unformatted files, which are described later in this chapter.

EXAMPLES:

1. Here is a program that create an output file, writes information to it, closes the
file and opens it again as an input file, and reads in the information:

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

int main( )
{
ofstream fout(“test”); // create output file

if(!fout) {
cout<< “Cannot open output file\n”;
return 1;
}

fout<<”Hello!\n”;
fout<<100<<’ ‘ <<hex<<100<<endl;

fout.close( )’;
Annamalai University
ifstream fin(“test”); //open input file

if(!fin) {
cout<<” Cannot open input file\n”;
return 1;
}

char str[80];
int i;

Page 121
Object Oriented Programming

fin>>str>>i;
cout<<str<<’ “<<i<<endl;

fin.close( );
return 0;
}

After you run this program, examine the contents of test. It will contain the following:

Hello!
100 64

As stated earlier, when the << and >> operators are used to perform file I/O,
information is formatted exactly as it would appear on the screen.

5.2.3 Unformatted, Binary I/O


Although formatted text files such as those produced by the preceding examples
are useful in a variety of situations, they do not have the flexibility of unformatted, binary
files. Unformatted files contains the same binary representation of the data as that used
internally by your program rather than the human-readable text that data is translated into
by the << and >> operators. Thus, unformatted I/O is also referred to as “raw” I/O. C++
supports a wide range of unformatted file I/O functions. The unformatted functions give
you detailed control over how files are written and read.

The lowest-level unformatted I/O functions are get( ) and put( ). You can read a
byte by using get( ) and write a byte by using put( ). These functions are members of all
input and output stream classes, respectively. The get( ) functions has many forms, but
the most commonly used version is shown here, along with put( ):

istream &get(char &ch);


ostream &put(char ch);

The get( ) function reads a single character from the associated stream and puts
that value in ch. It returns a reference to the stream. If a read is attempted at end-of-files,
on return the invoking stream will evaluate to false when usedin an expression. The put(
) functions writes ch to the stream and returns a reference to the stream.
Annamalai University
To read and write blocks of data, use the read( ) and write( ) functions which are
also members of the input and output stream classes, respectively. There prototype are
shown here:

istream &read(char *buf,streamsize num);


ostream &write(const char *buf,streamsize num);

The read( ) function reads num bytes from the invoking stream and puts them in
the buffer pointed to by buf. The write( ) function writes num bytes to the associated

Page 122
Object Oriented Programming

stream from the buffer pointed to by buf. The streamsize type is some form of integer.
An object of type streamsize is capable of holding the largest number of bytes that will
be transferred in any one I/O operation.

If the end of the file is reached before num characters have been read, read( )
simply stops, and the buffer contains as many character as available. You can find out
how many characters have been read by using the member function gcount( ), which has
this prototype:

streamsize gcount( );

It returns the number of characters read by the last unformatted input operation.
When you are using the unformatted file functions, most often you will open a file for
binary rather than the text operations. The reason for this is easy to understand:
specifying ios::binary prevents any character translation from occurring. This is
important when the binary representation of the data such as integers, floats and pointers
are stored in the file. However, it is perfectly acceptable to use the unformatted functions
on a file opened in text mode- as long as that file actually contains only text. But
remember, some character translation may occur.

EXAMPLES:

1. The next program will display the contents of any file on the screen. It uses the get( )
function.

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

int main(int argc, char *argv[ ])


{
char ch;

if(argc!=2) {
cout<<”Usage: PR <filename>\n”;
return 1;
} Annamalai University
ifstream in(argv[1], ios::in | ios::binary);
if(!in) {
cout<<”Cannot open file.\n”;
return 1;
}

while(!in.eof( )) {
in.get(ch);

Page 123
Object Oriented Programming

cout<<ch;
}

in.close( );

return 0;
}

2. This program uses put( ) to write character to a file until the user enters a dollar sign:

#include<iostream>
#include<fstream>
using namespace std;

int main(int argc, char *argv[ ])


{
char ch;

if(argc!=2) {
cout<<”Usage : WRITE <filename>\n”;
return 1;
}

ofstream out(argv[1] , ios::out | ios::binary);

if(!out) {
cout<<”Cannot open file .\n”;
return 1;
}

cout<<” Enter a $ to stop\n”;


do{
cout<<”; “;
cin.get(ch);
out.put(ch);
}while(ch!=’$’); Annamalai University
out.close( );

return 0;
}

Notice that the program uses get( ) to read characters from cin. This prevents leading
spaces from being discarded.

Page 124
Object Oriented Programming

5.2.4 More Unformatted I/O Functions


In addition to the form shown earlier, there are several different ways in which the
get( ) function is overloaded. The prototype for the three most commonly used
overloaded forms are shown here:

istream &get(char *buf, streamsize num);


istream &get(char *buf, streamsize num, char delim);
int get( );

The first form reads characters into the array pointed to by buf until either num-1
characters have been read, a newline is found, or the end of the file has been encountered.
The array pointed to by buf will be null terminated by get( ). If the newline character is
encountered in the input stream, its is not extracted. Instead, it remains in the stream until
the next input operation.

The second form reads character into the array pointed to by buf until either num-
1 characters have been read, the character specified by delim has been found, or the end
of the file has been encountered. The array pointed to by buf will be null terminated by
get( ). If the delimiter character is encountered in the input stream, its is not extracted.
Instead, it remains in the stream until the next input operation.

The third overloaded form of get( ) returns the next character from the stream. It
returns EOF if the end of the file is encountered. This form of get( ) is similar to C’s
getc( ) function. Another function that performs input is getline( ). It is a member of each
input stream class. Its prototypes are shown here:

istream &getline(char *buf, streamsize num);


istream &getline(char *buf, streamsize num, char delim);

The first form reads characters into the array pointed to by buf until either num-1
character have been read, a newline character has been found, or the end of the file has
been encountered. The array pointed to by buf will be null terminated by getline( ). If the
newline character is encountered in the input stream, it is extracted, but it is not put into
buf.

Annamalai University
The second form reads characters into the array pointed to by buf until either
num-1 character have been read, the character specify by delim has been found, or the
end of the file has been encountered. The array pointed to by buf will be null terminated
by getline( ). If the delimiter character is encountered in the input stream, it is extracted,
but it is not put into buf.

As you can see, the two versions of getline( ) are virtually identical to the
get(buf, num) and get(buf,num,delim) versions of get( ). Both read characters from
input and put them into the array pointed to by buf until either num-1 characters have
been read or until the delimiter character or the end of the file is encountered. The

Page 125
Object Oriented Programming

difference between get( ) and getline( ) is that getline( ) read and removes the delimiter
from the input stream; get( ) does not.

You can obtain the next chapter in the input stream without removing it from that
stream by using peek( ). This function is a member of the input stream classes and has
this prototype:

int peek( );

It returns the next character in the stream; it returns EOF if the end of the file is
encountered.

You can return the last character read from a stream to that stream by using
putback( ), which is a member of the input stream classes. Its prototype is shown here:

istream &putback(char c);

where c is the last character read.

When output is performed, data is not immediately written to the physical device
linked to the string. Instead, information is stored in an internal buffer until the buffer is
full. Only then are the contents of the buffer written to disk. However, you can force the
information to be physically written to disk before the buffer is full by calling flush( ).
flush( ) is a member of the output stream classes and has this prototype:

ostream &flush( );

Calls to flush( ) might be warranted when a program is going to be used in


adverse environments (in situations where power outages occur frequently, for example).

EXAMPLE:

1. As you know, when you use >> to read a string, it stops reading when the first
white space character is encountered. This makes it useless for reading a string containing
spaces. However, you can overcome this problem by using getline( ), as this program
illustrates:
Annamalai University
//Use getline( ) to read a string that contain spaces.
#include<iostream>
#include<fstream>
using namespace std;
int main( )
{
char str[80];
cout<<” Enter your name:”;
cin.getline(str, 79);
cout<<str<<”\n”;
return 0;

Page 126
Object Oriented Programming

}
In this program, the delimiter used by getline( ) is the newline. This makes
getline( ) act much like the standard gets( ) function.

5.2.5 Random Access

In C++’s I/O system, you perform random access by using the seekg( ) and
seekp( ) functions, which are members of the input and output stream classes,
respectively. Their most common forms are shown here:

istream &seekg(off_type offset, seekdir origin);


istream &seekp(off_type offset, seekdir origin);

Here off_type is an integer type defined by ios that is capable of containing the largest
valid value that offset can have. Seekdir is an enumeration defines by ios that has these
values:

Value Meaning
ios::beg seek from beginning
ios::cur seek from current location
ios::end seek from end

The C++ I/O system manages two pointers associated with the file. One is the get
pointer, Which specifies where in the file the next input operation will occur. The other is
the put pointer, which specifies where in the file the next output operation will occur.
Each time an input or output operation will takes place, the appropriate pointer is
automatically sequentially advanced. However, by using the seekg( ) and seekp( )
functions, it is possible to access the file in the nonsequential fashion.

The seekg( ) function moves the associated file’s current get pointer offset number
of bytes from the specified origin. The seekp( ) function moves the associated file’s
current put pointer offset number of bytes from the specified origin.

In general, files that will be accessed via seekg( ) and seekp( ) should be opened
for binary file operations. This prevents character translations from occurring which may
affect the apparent position of an item within a file.
Annamalai University
You can determine the current position of each file pointer by using these member
function:
pos_type tellg( );
pos_type tellp( );

Here pos_type is an integer type defined by ios that is capable of holding the
largest value that defines a file position.

Page 127
Object Oriented Programming

There are overloaded versions of seekg( ) and seekp( ) that moves the file pointer
to the location specified by the return value of tellg( ) and tellp( ). Their prototype are
shown here.

istream &seekg(pos_type position);


ostream &seekp(pos_type position);

EXAMPLES:

1. The following program demonstrates the seekp( ) function. It allows you


change the specific character in a file. Specify a file name on the command line, followed
by the number of the byte in the file you want to change, following by the new character.
Notice that the file is opened for read/write operations.

#include<iostream.h>
#include<fstreseam.h>
#include<cstdlib.h>
using namespace std;
int main(int argc, char *argv[ ])
{
if(argc!=4) {
cout<<”Usage : CHANGE <filename> <byte> <char>\n”;
return 1;
}

fstream out(argv[1], ios::in | ios::out | ios::binary);


if(!out) {
coout<<”Cannot open file.\n”;
return 1; Annamalai University
}

out.seekp(atoi( argv[2] ), ios::beg);

out.put(*argv[3]);
out.close( );

Page 128
Object Oriented Programming

return 0;
}

2 .The next program uses seekg( ) to position the get pointer into the middle of a file and
then displays the contents of that file from that point. The name of the file and the
location to begin reading from are specified on the command line.

// Demonstrate seekg( ).
#include<iostream.h>
#include<fstream.h>
#include<cstdlib.h>
using namespace std;

int main(int argc, char *argv[ ])


{
char ch;

if(argc!=3) {
cout<<”Usage : LOCATE <filename> <loc>\n”;
return 1;
}

ifstream in(argv[1], ios::in | ios::binary);

if(!in) {
cout << “Cannot open input file.\n”;
return 1;
}

in.seekg(atoi(argv[2]), ios::beg);

while(!in.eof()) {
in.get(ch);

}
Annamalai University
cout<<ch;

in.close( );
return 0;
}

Page 129
Object Oriented Programming

5.2.6 Checking The I/O Status


The C++ I/O system maintains status information about the outcome of each I/O
operation. The current status of an I/O stream is described in an object of type iostate,
which is an enumeration defined by ios that includes these members:

Name Meaning

goodbit No error occurred.


eofbit End-of-file has been encountered.
failbit A nonfatal I/O error has occurred.
badbit A fatal I/O error has occurred.

For older compilers, the I/O status flags are held in an int rather than an object of
type iostate.
There are two ways in which you can obtain I/O status information. First, you can
call the rdstatus( ) function, which is a member of ios. It has this prototype:

iostate rdstate( );

It returns the current status of the error flags. As you can probably guess from
looking at the preceding list of flags, rdstate( ) returns goodbit when no error has
occurred. Otherwise, an error flag is return.
The other way you can determine whether an error has occurred is by using one or
more of these ios member functions.

bool bad( );
bool eof( );
bool fail( );
bool good( );

The eof( ) function was discussed earlier. The bad( )function return true if
badbit( )is set. The fail( ) function return true if failbit is set. The good( )function return
true if there are no errors. Otherwise they return false.
Once an error has occurred, it might need to be cleared before your program
continues. To do this, use the ios member function clear( ) whose prototype is shown
here:
Annamalai University
void clear(iostate flags=ios::goodbit);

If flags is goodbit(as it is by default), all error are cleared. Otherwise, set flags to
the settings you desire.

EXAMPLES:

1. The following program illustrates rdstate( ). It displays the content of a text


file. If an error occurs, the function report it by using checkstatus( )

Page 130
Object Oriented Programming

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

void checkstatus(ifstream &in);

int main(int args, char *argv[ ])


{
if(argc!=2) {
cout<<”Usage :DISPLAY <filename>\n”;
return 1;
}
ifstream in(argv[1]);

if(!in) {
cout<<”Cannot open file.\n”;
return 1;
}

char c;
while(in.get(c)) {
cout<<c;
checkstatus(in);
}

checkstatus(in); // check final status


in.close( );
return 0;
}

void checkstatus(ifstream &in)


{
ios::iostate i;
i = in.rdstate( );
if(i & ios::eofbit)
Annamalai University
cout<<”EOF encountered \n”;
else if(i & ios::failbit)
cout<<”Non-fatal I/O error \n”;
else if(i & ios::badbit)
cout<<”Fatal I/O error\n”;
}

The preceding program will always report at least one “error”. After the while
loop ends, the final call to checkstatus( ) reports, as expected, that an EOF has been
encountered.

Page 131
Object Oriented Programming

5.2.7 Customized I/O And Files


In the preceding chapter, you learned how to overload the insertion and extraction
operators relative to your own classes. In that chapter, only console I/O was performed.
However, because all C++ streams are the same, the same overloaded insertion function,
for example, can be used to output to the screen or to a file with no changes whatsoever.
This is one of the most important and useful features of C++’s approach to I/O.

As stated in the previous chapter, overloaded inserters and extraction, as well as


I/O manipulators, can be used with any stream as long as they are written in a I/O
function, its use is, of course, limited to only that stream. This is why you were urged to
generalize your I/O functions whenever possible.

EXAMPLES:

1. In the following program, the coord class overloads the << and >> operators.
Notice that you can use the operator functions to write both to the screen and
to a file.

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

class coord {
int x,y;
public:
coord(int i, int j) {x = i; y = j ;}
friend ostream &operator<<(ostream &stream, coord ob);
friend istream &operator>>(istream &stream, coord &ob);
};

ostream &operator<<(ostream &stream, coord ob)


{
stream << ob.x << ‘ ‘ <<ob.y <<”\n”;

return stream;
} Annamalai University
istream &operator>>(istream &stream, coord &ob);
{
stream >> ob.x >> ob.y <<”\n”;
return stream;
}

int main( )
{

Page 132
Object Oriented Programming

coord o1(1, 2) , o2(3, 4);


ofstream out(“test”);

if(!out) {
cout<< “Cannot open output file.\n”;
return 1;
}

out<< o1 <<o2;
out.close( );
ifstream in(“test”);

if(!in) {
cout<<”Cannot open input file \n”;
return 1;
}

coord o3(0 , 0), o4(0 , 0);


in >> o3 >> o4;
cout <<o3 <<o4;
in.close( );
return 0;
}

1. All of the I/O manipulators can be used with files. For example, in this
reworked version of a program presented earlier in this chapter, the same
manipulator that writes to the screen will also write to a file:

#include<iostream.h>
#include<fstream.h>
#include<iomanip.h>
using namespace std;

// Attention:
ostream &atn(ostream &stream)
{
Annamalai University
stream <<”Attention:”;
return stream;
}

//please note:
ostream &note(ostream &stream)
{
stream<<”Please Note:”;
return stream;
}

Page 133
Object Oriented Programming

int main( )
{
ofstream out(“test”);
if(!out) {
cout<<”Cannot open output file. \n”;
return 1;
}

//write to screen
cout<< atn << “High voltage circuit\n”;
cout<< note << “Turn off all lights \n”;

//write to file
out<< atn << “High voltage circuit\n”;
out<< note << “Turn off all lights \n”;
out.close( );

return 0;
}

5.2.8 Pointers To Derived Classes


Although as it was discussed earlier, C++ pointers at some length, one special
aspect was deferred until now because it relates specifically to virtual functions. The
feature is this: A pointer declared as a pointer to a base class can also be used to point to
any class derived from that base. For example, assume two classes called base and
derived, where derived inherits base. Given this situation, the following statements are
correct:

base *p; // base class pointer

base base_ob; // object of type base


derived derived_ob; // object of type derived

//p can, of course, point to base objects


p = &base_ob; //p points to base object
Annamalai University
// p can also point to derived objects without error
p = &derived_ob; // p points to derived object

As the comments suggest, a base pointer can point to an object of any class derived from
that base without generating a type mismatch error.

1Although you can use a base pointer to point to a derived object, you can access only
those members of the derived object that were inherited from the base. This is because

Page 134
Object Oriented Programming

the base pointer has knowledge only of the base class. It knows nothing about the
members added by the derived class.

While it is permissible for a base pointer to point to a derived object, the reverse
is not true. A pointer of the derived type cannot be used to access an object of the base
class. (A type cast can be used to overcome this restriction, but its use is not
recommended practice.)

One final point: Remember that pointer arithmetic is relative to the data type the
pointer is declared as pointing to. Thus, if you point a base pointer to a derived object and
then increment that pointer, it will not be pointing to the next derived object. It will be
pointing to (what it thinks is) the next base object. Be careful about this.

EXAMPLE:

1. Here is a short program that illustrates how a base class pointer can be used to
access a derived class:

// Demonstrate pointer to derived class.


#include <iostream>
using namespace std;

class base {
int x;
public:
void setx(int i) { x = i; }
int getx( ) { return x; }
};

class derived : public base {


int y;
public:
void sety(int i) { y = i; }
int gety( ) { return y; }
};

int main( )
{
Annamalai University
base *p; // pointer to base type
base b_ob; //object of base
derived d_ob; //object of derived

// use p to access base object


p = &b_ob;
p->setx(10); //access base object
cout << “Base object x: “ << p->getx( ) << ‘\n’;

Page 135
Object Oriented Programming

//use p to access derived object


p = &d_ob; // point to derived object
p->setx(99); // access derived object

// can’t use p to set y, so do it directly


d_ob.sety(88);
cout << “Derived object x: “ << p->getx( ) <<’\n’;
cout << “Derived object y: “ << d_ob.gety( ) << ‘\n’;

return 0;
}

Aside from illustrating pointers to derived classes, there is no value in using a


base class pointer in the way shown in this example. However, in the next section you
will see why base class pointers to derived objects are so important.

5.2.9 Introduction To Virtual Functions


A virtual function is a member function that is declared within a base class and
redefined by a derived class. To create a virtual function, precede the function’s
declaration with the keyword virtual. When a class containing a virtual function is
inherited, the derived class redefines the virtual function relative to the derived class. In
essence, virtual functions implement the “one interface, multiple methods” philosophy
that underlies polymorphism. The virtual function within the base class defines the form
of the interface to that function. Each redefinition of the virtual function by a derived
class implements its operation as it relates specifically to the derived class. That is, the
redefinition creates a specific method. When a virtual function is redefined by a derived
class, the keyword virtual is not needed.

A virtual function can be called just like any other member function. However,
what makes a virtual function interesting-and capable of supporting run-time
polymorphism-is what happens when a virtual function is called through a pointer. From
the preceding section you know that a base class pointer can be used to point to a derived
class object. When a base pointer points to a derived object that contains a virtual
function and that virtual function is called through that pointer, C++ determines which
version of that function will be executed based upon the type of object being pointed to
Annamalai University
by the pointer. And, this determination is made at run time. Put differently, it is the type
of the object pointed to at the time when the call occurs that determines which version of
the virtual function will be executed. Therefore, if two or more different classes are
derived from a base class that contains a virtual function, then when different objects are
pointed to by a base pointer, different versions of the virtual function are executed. This
process is the way that run-time polymorphism is achieved. In fact, a class that contains a
virtual function is referred to as a polymorphic class.

Page 136
Object Oriented Programming

EXAMPLE:

1. Here is a short example that uses a virtual function:

// A simple example using a virtual function.


#include <iostream.h>
using namespace std;

class base {
public:
int i;
base(int x) { i = x; }
virtual void func( )
{
cout << “Using base version of func( ) : “;
cout << i << ‘\n’;
}
};

class derived1 : public base {


public:
derived1(int x) : base(x) { }
void func( )
{
cout << “Using derived1’s version of func( ): “;
cout << i*i << ‘\n’;
}
};

class derived2 : public base {


public:
derived2(int x) : base(x) { }
void func( )
{
cout << “Using derived2’s version of func( ): “;
cout << i+i << ‘\n’;

};
} Annamalai University
int main( )
{
base *p;
base ob(10);
derived1 d_ob1(10);
derived2 d_ob2(10);

Page 137
Object Oriented Programming

p = &ob;
p->func( ); //use base’s func( )

p = &d_ob1;
p->func( ); //use derived1’s func( )

p = &d_ob2;
p->func( ); //use derived2’s func( )

return 0;
}

This program displays the following output:

Using base version of func( ) : 10


Using derived1’s version of func( ) : 100
Using derived2’s version of func( ) : 20

The redefinition of a virtual function inside a derived class might, at first, seem
somewhat similar to function overloading. However, the two processes are distinctly
different. First, an overloaded function must differ in type and/or number of parameters,
while a redefined virtual function must have precisely the same type and number of
parameters and the same return type.(In fact, if you change either the number or type of
parameters when redefining a virtual nature is lost.) Further, virtual functions must be
class members. This is not the case for overloaded functions. Also, while destructor
functions can be virtual, constructors cannot. Because of the difference between
overloaded functions and redefined virtual functions, the term overriding is used to
describe virtual function redefinition.

As you can see, the example program creates three classes. The base class defines
the virtual function func( ). This class is then inherited by both derived1 and derived2.
Each of these classes overrides func( ) with its individual implementation. Inside main(
), the base class pointer p is declared along with objects of type base, derived1 and
derived2. First, p is assigned the address of ob(an object of type base). When func( ) is
called by using p, it is the version in base that is used. Next, p is assigned the address of
d_ob1 and func( ) is called again. Because it is the type of the object pointed to that
Annamalai University
determines which virtual function will be called, this time it is the overridden version in
derived1 that is executed. Finally, p is assigned the address of d_ob2 and func( ) is
called again. This time, it is the version of func( ) defined inside derived2 that is
executed.

The key points to understand from the preceding example are that the type of the
object being pointed to determines which version of an overridden virtual function will
be executed when accessed via a base class pointer, and that this decision is made at run
time.

Page 138
Object Oriented Programming

5.2.10 More About Virtual Functions


From the preceding section illustrates, sometimes when a virtual function is
declared in the base class there is no meaningful operation for it to perform. This
situation is common because often a base class does not define a complete class by itself.
Instead, it simply supplies a core set of member functions and variables to which the
derived class supplies the remainder. When there is no meaningful action for a base class
virtual function to perform, the implication is that any derived class must override this
function. To ensure that this will occur, C++ supports pure virtual functions.

A pure virtual function has no definition relative to the base class. Only the
function’s prototype is included. To make a pure virtual function, use this general form:

virtual type func-name(parameter-list)=0;

The key part of this declaration is the setting of the function equal to 0. This tells
the compiler that no body exists for this function relative to the base class. When a virtual
function is made pure, it forces any derived class to override it. If a derived class does
not, a compiler-time error results. Thus, making a virtual function pure is a way to
guarantee that a derived class will provide its own redefinition.

When a class contains at least one pure virtual function, it is referred to as an


abstract class. Since an abstract class contains at least one function for which no body
exists, it is, technically, an incomplete type, and no objects of that class can be created.
Thus, abstract classes exist only to be inherited. They are neither intended nor able to
stand alone. It is important to understand, however, that you can still create a pointer to
an abstract class, since it is through the use of base class pointers that run-time
polymorphism is achieved.(It is also permissible to have a reference to an abstract class.)

When a virtual function is inherited, so is its virtual nature. This means that when
a derived class inherits a virtual function from a base class and then the derived class is
used as a base for yet another derived class, the virtual function can be overridden by the
final derived class ( as well as the first derived class ). For example, if base class B
contains a virtual function called f( ), and D1 inherits B and D2 inherits D1, both D1 and
D2 can override f( ) relative to their respective classes.

5.2.11 Applying Polymorphism


Annamalai University
Now that you know how to use a virtual function to achieve run-time
polymorphism, it is time to consider how and why to use it. As has been stated many
times in this book, polymorphism is the process by which a common interface is applied
to two or more similar ( but technically different) situations, thus implementing the “one
interface, multiple methods” philosophy. Polymorphism is important because it can
greatly simplify complex systems. A single, well-defined interface is used to access a
number of different but related actions, and artificial complexity is removed. In essence,
polymorphism allows the logical relationship of similar actions to become apparent; thus,
the program is easier to understand and maintain. When related actions are accessed
through a common interface, you have less to remember.

Page 139
Object Oriented Programming

There are two terms that are often linked to OOP in general and to C++
specifically. They are early binding and late binding. It is important that you know what
they mean. Early binding essentially refers to those events that can be known at compile
time. Specifically, it refers to those function that can be resolved during compilation.
Early bound entities include “normal” functions, overloaded functions, and nonvirtual
member and friend functions. When these types of functions are compiled, all address
information necessary to call them is known at compile time. The main advantage of
early binding (and the reason that it is so widely used) is that it is very efficient. Calls to
functions bound at compile time are the fastest types of function calls. The main
disadvantage is lack of flexibility.

Late binding refers to events that must occur at run time. A late bound function
call is one in which the address of the function to be called is not known until the
program runs. In C++ , a virtual function is a late bound object. When a virtual function
is accessed via a base class pointer, the program must determine at run time what type of
object is being pointed to and then select which version of the overridden function to
execute. The main advantage of late binding is flexibility at run time. Your program is
free to respond to random events without having to contain large amounts of
“contingency code.” Its primary disadvantage is that there is more overhead associated
with a function call. This generally makes such calls slower than those that occur with
early binding.

Because of the potential efficiency trade-offs, you must decide when it is


appropriate to use early binding and when to use late binding.

5.2.12 Templates And Exception Handling

Generic Functions
A generic function defines a general set of operations that will be applied
to various types of data. A generic function has the type of data that it will operate upon
passed to it will operate upon passed to it as a parameter. Using this mechanism, the same
general procedure an can be applies to a wide range of data. As you know, many
algorithms are logically the same no matter what type of data is being operated upon . For
example, the quick sort algorithm is the same whether it is applied to an array of integers
or an array of floats. It is just that the type of the data being sorted id different. By
Annamalai University
creating a generic function, you can define, independent of any data, the nature of the
algorithm. Once this is done, the compiler automatically generates the correct code for
the type of data is actually used when you executes the function. In essence, when you
create a generic function you are creating a function that can automatically overload
itself.

A generic function is created using the keyword template. The normal meaning
of the word template accurately reflects the keyword’s use in C++. It is used to create a
template (or framework) that describes what a function will do, leaving it to the compiler

Page 140
Object Oriented Programming

to fill in the details as needed. The general form of a template function definition is
shown here:

Template<class Ttype> ret-type func-name(parameter list)


{
//body of function
}

Here Ttype is a placeholder name for a data type used by the function. This mane can be
used within the function definition. However, it is only a placeholder ; the compiler will
automatically replace this placeholder with an actual data type when it creates a specific
version of the function.

Although the use of the keyword class to specify a generic type in a template
declaration is traditional, you can also use the keyword typename.

EXAMPLE:

1. The following program creates a generic function that swaps the value of the two
variables it is called with. Because the general process of exchanging two values
is independent of the type of the variables, this process is a good choice to be
made into a generic function.

// Function template example.


#include<iostream.h>
using namespace std;
//This is a function templates.
Template <class X> void swapargs (X &a, X &b)
{
X temp;

temp = a;
a = b;
b = temp;
}
int main( )
{ Annamalai University
int i=10, j=20;
float x=10.1, y=23.3;

cout<<”Original i, j: “<<i<< “ “ <<j <<endl;


cout<<“Original x,y:“<<x<<” “<<y<<endl;

swapargs(i, j); // Swap Integers


swapargs(x, y); // Swap Float

Page 141
Object Oriented Programming

cout<<”Swapped i, j: “<<i<< “ “ <<j <<endl;


cout<<“Swapped x,y:“<<x<<” “<<y<<endl;
return 0;
}

The keyword template is used to defined a generic function


The line

Template <class X> void swapargs(X &a, X &b)

Tells the compiler two things: that a templates is being created and generic
definition is beginning. Here X is a generic type that is used as a placeholder. After the
template portion, the function swapargs( ) is declared, using X as the data type of the
values that will be swapped. In main( ) the swapargs( ) function is called using two
different types of data.: Integer and float. Because swapargs( ) is a generic function, the
compiler automatically created two versions of swapargs( )- one that will exchange
floating-point values. You should compile and try this program now.

Here are some other terms that are some time used when templates are discussed
and that you might encounter in other C++ literature. First, a generic function(that is, a
function definition preceded by a template statement) is also called a template function.
When the compiler creates a specific version of this function, it is said to have created a
generated function. The act of generating a function is referred to as instantiating it. Put
differently, a generated function is a specific instance of a template function.

Generic Classes
In addition to definition generic functions, you can also define generic classes.
When you do this, you create a class that defines all algorithms used by that class, but the
actual type of the data being manipulated will be specified as a parameter when object of
that class are created.

Generic classes are useful when a class contains generalizable logic. For example,
he same algorithm that maintains a queue of integers will also work for a queue of
characters. Also, the same mechanism that maintains a linked list of mailing addresses
will also maintain a linked list of auto part information. By using a generic class, you can
Annamalai University
create a class that will maintain a queue, a linked list, and so on for any type of data. The
compiler will automatically generate the correct type of object based upon the type you
specify when the object is created.

The general form of a generic class declared is shown here:

Template < class Ttype > class class-name {


.
.
.

Page 142
Object Oriented Programming

Here Ttype is the placeholder type name that will be specified when a class is
instantiated. If necessary, you can define more than one generic data type by using a
comma-separated list.

Once you have created a generic class, you create a specific instant of that class
by using the following general form:

class-name < type> ob;

Here type is the name of the data that the class will be operating upon.

Member functions of generic class are, themselves, automatically generic. They


need not be explicitly specified as such using template.

As you will see later, C++ provides a library that is built upon template classes.
This library is usually referred to as the Standard Template Library, or STL for short. It
provides generic versions of the most commonly used algorithms and data structures. If
you want to use the STD effectively, you’ll need a solid understanding of template
classes and their syntax:

EXAMPLE:

1. This program creates a very simple generic singly linked list class. It then
demonstrates the class by creating a linked list that stores characters.

// A simple generic linked list


#include<iostream.h>
using namespaces std;

template <class data_t> class list {


data_t data;
list *next;
public:
Annamalai University
list(data_t d);
void add(list *node) { node->next = this; next = 0; )
list *getnext( ) { return next; }
data_t getdata( ) { return data; }
};

template <class data_t> list <data_t>::list(data_t d)


{
data = d;
next = 0;

Page 143
Object Oriented Programming

int main( )
{
list<char> start(‘a’);
list<char> *p, *last;
int i;

// build a list
last = &start;
for(i=1;i<26;i++) {
p=new list<char> (‘a’ + i);
last=p;

// follow the list


p = &start;
while(p) {
cout << p->getdata( );
p=p->getnext( );
}
return 0;
}

As you can see, the declaration of a generic class is similar to that of a generic
function. The actual type of the data stored by the list is generic in the class declaration.
It is not until an object of the list is declared that the actual data type is determined. In
this example, object and pointers are created inside main( ) that specifies that the data
type of the list will be char. Pay special attention to this declaration:

List < char > start(‘a’);

Notice how the desired data type is passed inside the angle brackets.

You should enter and executes this program. It builds a linked list that contain the
character of the alphabet and then display them. However, by simply changing the type of
the data specified when list objects are created, you can change the type of the data stored
Annamalai University
by the list . For example, you could create another object that stores integer by using this
declaration.

List < int > int_start(1);

You can also use list to store data types that you create. For example, if you want
to store address information, use this structure:

Struct addr {
Char name[40];

Page 144
Object Oriented Programming

Char street[40];
Char city[30];
Char state[3];
Char zip[12];
}

Then, to use list to generate objects that will store objects of type addr, use a
declaration like this (assuming that structvar contains a valid addr structure);

List <addr> obj(structvar);

5.2.13 Exception Handling


C++ provides a built-in error handing mechanism that is called exception
handling. Using exception handling, you can more easily manage and responds to run-
time error. C++ exception handling is built upon three keywords : try, catch, and throw.
In the most general terms, program statement that you want to monitor for exception are
contained in a try block. If an exception (i.e., an error ) occurs within the try block, it is
thrown(using throw).The exception is caught, using catch, and processed. The following
elaborates upon this general description.

As stated, any statement that throws an exception must have been executed from
within a try block. A function called from within try block can also throw an exception.)
Any exception must be caught by a catch statement that immediately follows the
exception.. the general form of try and catch is shown here:

try {
//try block
}
catch (type1 arg) {
//catch block
}
catch (type2 arg) {
//catch block
}
catch (type3 arg) {
Annamalai University
//catch block
}
.
.
.
catch (typeN arg) {
//catch block
}

The try block must contain the portion of your program that you want to monitor
for error. This can be as specified as monitoring a few statement with in one function or

Page 145
Object Oriented Programming

as all-encompassing as enclosing the main( ) function code within a try block (which
effectively cause the entire program to be monitored.)

When an exception is thrown, it is caught by its corresponding catch statement,


which processes the exception. There can be more than one catch statement associated
with a try. The catch statement that is used to determine by the type of the exception.
That is, if the data type specified by a catch matches that of the exception, that catch
statement is executed (and all others are bypassed. When an exception is caught, arg will
receive its value. If you don’t need to access to the exception itself, specify only type in
the catch clause-arg is optional. Any type of the data can be caught, including classes
that you create. In fact, class types are frequently used as exceptions.

The general form of the throw statement is shown here:

throw exception;

throw must be executed either from within the try block proper or from any function that
the code within the block calls(directly or indirectly.) exception is the value thrown.

If you throw an exception for which there is no applicable catch statement, an


abnormal program termination might occur. If your compiler compiles with Standard
C++, throwing an unhandled exception causes the standard library function terminate( )
to be invoked. By default terminate( )calls abort( ) to stop your program but you can
specify your own termination handler, if you like. You will need to refer to your
compiler’s library reference for the detail.

EXAMPLE:

1. Here is a simple example that shows the way C++ exception handling operators:

//A simple exception handling example.


#include<iostream.h>
using namespaces std;

int main( )
{
Annamalai University
cout<< “Start \n”;

try { // start a try block


cout<<”Inside try block\n”;
throw 10; // throw an error
cout<<”This will not execute”;
}
catch ( int i ) { // catch an error
cout<<”Caught one! Number is:”;
}

Page 146
Object Oriented Programming

cout<<”End”;

return 0;
}

This program display the following output.

Start
Inside try block
Catch one! Number is 10
End

Look carefully at this program. As you can see , there is a try block containing
three statement and a catch(int i) statement that process an integer exception. Within the
try block, only two of the three statements will execute: the first cout statement and the
throw. Once an exception has been thrown, control passes to the catch expression and
the try block is terminated. That is, catch is not called. Rather, program execution is
transferred to it.(The stack is automatically reset as needed to accomplish this.) Thus, the
cout statement following the throw will never execute.

After the catch statement executes, program control continues with the statement
following the catch. Often however, a catch block will end with a call to exit( ), abort( ),
or some other function that causes program terminated because exception handling is
frequently used to handle catastrophic error.

2. As mentioned, the type of the exception must match the type specified in the
catch statement. For example, in the preceding example, if you change the type in
the catch statement to double, the exception will not be catch and abnormal
termination will occurs. This changes is shown hare:

// This example will not be work


#include<iostream.h>
using namespace std;

int main( )
{ Annamalai University
cout<<”Start\n”;

try { // start a try block


cout<<”Inside try block\n”;
throw 10; // throw an error
cout<<”This will not execute”;
}
catch (double i ) { // Won’t work for an int exception
cout<<”Caught one! Number is:”;

Page 147
Object Oriented Programming

cout<<I<<”\n”;
}

cout<<”End”;

return 0;
}

This program produces the following output because the integer exception will not be
catch by a double catch statement.
Start
Inside try block
Abnormal program termination

3. An exception can be thrown from a statement that is outside the try block as
long as the statement is within a function that is called from within the try block. For
example, this is a valid program.
/* Throwing an exception from a function outside the try block.*/

#include<iostream>
using namespace std;

void Xtest(int test)


{
cout<<”Inside Xtest, test is: “<<test<<”\n”;
if(test) throw test;
}

int main( )
{
cout<<”Start\n”;
try { // start a try block
cout<<”Inside try block\n”;
Xtest(0);
Xtest(1);
Xtest(2);
} Annamalai University
catch ( int i ) { // catch an error
cout<<”Caught one! Number is:”;
cout<<i<<”\n”;
}
cout<<”End”;
return 0;
}

This program produces the following output

Page 148
Object Oriented Programming

Start
Inside try block
Inside Xtest, test is:0
Inside Xtest, test is:1
caught one! Number is:1
end

4. A try block can be localized to a function. When this is the case, each time the
function is entered, the exception handling relative to that function is reset. For example,
examine this program:

#include <iostream.h>
using namespace std;
// A try/catch can be inside a function other that main( ).
void Xhandler (int test)
{
try{
if(test) throw test;
}
catch(int i) {
cout << “Caught One! Ex. #: “ << i << ‘\n’;
}
}

int main( )
{
cout << “start\n”;
Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
cout << “end”;
return 0;
}

This program displays this output:

start
Annamalai University
Caught One! Ex. #: 1
Caught One! Ex. #: 2
Caught One! Ex. #: 3
end

As you see, three exceptions are thrown. After each exception, the function
returns. When the function is called again, the exception handling is reset.

Page 149
Object Oriented Programming

5. As stated earlier, you can have more than one catch associated with a try. In
fact, it is common to do so. However, each catch must catch a different type of
exception. For example, the following program catches both integers and strings:

#include <iostream>
using namespace std;

// Different types of exceptions can be caught.


void Xhandler(int test)
{ try{
if(test) throw test;
else throw “Value is zero”;
}
catch(int i) {
cout << “Caught One! Ex. #: “ << i << ‘\n’;
}
catch(char *str) {
cout << “Caught a string: “;
cout << str << ‘\n’;
}
}
int main( )
{
cout << “start\n”;

Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
cout << “end”;

return 0;
}

This program produces the following output:

start Annamalai University


Caught One! Ex. #: 1
Caught One! Ex. #: 2
Caught a string: Value is zero
Caught One! Ex. #: 3
End

As you can see, each catch statement responds only to its own type.
In general, catch expressions are checked in the order in which they occur in a
program. Only a matching statement is executed. All other catch blocks are ignored.

Page 150
Object Oriented Programming

More About Exception Handling


There are several additional features and nuances to C++ exception handling that
can make it easier and more convenient to use.

In some circumstances you will want an exception handler to catch all exceptions
instead of just a certain type. This is easy to accomplish. Simply use this form of catch:

catch(…) {
// process all exceptions
}

Here the ellipse matches any type of data.

You can restrict the type of exceptions that a function can throw back to its caller.
Put differently, you can control what type of exceptions a function can throw outside of
itself. In fact, you can also prevent a function from throwing any exceptions whatsoever.
To apply these restrictions, you must add a throw clause to the function definition. The
general form of this is shown here:

ret-type func-name(arg-list) throw(type-list)


{
//…
}

Here only those data types contained in the comma-separated type-list may be
thrown by the function. Throwing any other type of expression will cause abnormal
program termination. If you don’t want a function to be able to throw any exceptions, use
an empty list.
If your compiler compiles with standard C++, when a function attempts to throw
a disallowed exception the standard library function unexpected( ) is called. By default,
this causes the termination( ) function to be called, which causes abnormal program
termination. However, you can specify your own termination handler, if you like. You
will need to refer to your compiler’s documentation for directions on how this can be
accomplished.

Annamalai University
If you wish to rethrow an expression from within an exception handler, you can
do so by simply calling throw, by itself, with no exception. This causes the current
exception to be passed on to an outer try/catch sequence.

Handling Exception Thrown By NEW


Earlier you learned that the modern specification for the new operator states that
it will throw an exception if an allocation request fails. Earlier, exceptions had not yet
been discussed, a description of how to handle that exception was deferred until later.
Now the time has come to examine precisely what occurs when new fails.

Page 151
Object Oriented Programming

Before we begin, it is necessary to state that the material in this section describes
the behavior of new as specified by Standard C++. As you should recall from chapter 4,
the precise action that new takes on failure has been changed several times since C++
was invented. Specifically, when C++ was first invented, new returned null on failure.
Later this was changed such that new caused an exception on failure. Also, the name of
this exception has changed over time. Finally, it was decided that a new failure will
generate an exception by default, but that a null pointer could be returned instead, as an
option. Thus, new has been implemented differently, at different times, by compiler
manufacturers. Although all compilers will eventually implement new in compliance
with Standard C++, not all currently do. If the code examples shown here do not work
with your compiler, check your compiler’s documentation for details on how it
implements new.

In Standard C++, when an allocation request cannot be honored, new throws a


bad_alloc exception. If you don’t catch this exception, your program will be terminated.
Although this behavior is fine for short sample programs, in real applications you must
catch this exception and process it in some rational manner. To have access to this
exception, you must include the header <new> in your program.

Originally this exception was called xalloc, and at the time of this writing many
compilers still use the older name. However, bad_alloc is the name specified by Standard C++,
and it is the name that will be used in the future

In Standard C++ it is also possible to have new return null instead of throwing an
exception when an allocation failure occurs. This form of new is most useful when you
are compiling older code with a modern C++ compiler. It is also valuable when you are
replacing calls to malloc( ) with new. This form of new is shown here.

p_var = new(nothrow) type;

Here p_var is a pointer variable of type. The nothrow form of new works like the
original version of new from years ago. Since it returns null on failure, it can be “dropped
into” older code and you won’t have to add exception handling. However, for new code,
exceptions provide a better alternative.

EXAMPLE:
Annamalai University
1. Here is an example of new that uses a try/catch block to monitor for an
allocation failure.

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

int main( )
{
int *p;

Page 152
Object Oriented Programming

try {
p = new int; // allocate memory for int
} catch (bad_alloc xa) {
cout << “Allocation failure.\n”;
return 1;
}

for(*p = 0; p < 10; (p) ++)


cout << *p << “ “;

delete p; // free the memory


return 0;
}

Here if an allocation failure occurs, it is caught by the catch statement.

5.3) Revision Points


MANIPULATOR: A data object that is used with the insertion and extraction
operators.

get ( ): The get ( ) function reads a single character from the associated stream.

put ( ): The put ( ) functions writes a character to the stream and returns a reference
to the stream.

read ( ): The read ( ) function reads bytes from the invoking stream and puts them in
buffer pointer.

write ( ): The write ( ) function writes bytes to the associated stream from the buffer
pointer.

streamsize: This type is some from of integer. This has the capacity to hold the
Annamalai University
largest number of bytes that will be transferred in any I\P operations

putback ( ): This can return the last character read from a stream.

VIRTUAL FUNCTION: A virtual function is a member function that is declared


within a base class and redefined by a derived class

POLYMORPHISM: A property by which we can send the same message to objects


of several different classes.

POINTER: A data type that holds the address of a location of memory.

Page 153
Object Oriented Programming

5.4) Intext Questions

1. Give the syntax for creating user defined manipulators


2. Distinguish the functions of ‘cin’ and ‘getline’ which are used for input.
3. How is polymorphism achieved at compile time.
4. List out any differences between a virtual function and a overloaded function.
5. What are unformatted I/O functions?
6. What is virtual function?
7. What are exception handlings?

5.5) Summary
 A manipulator consolidates a sequence of several separate I/O operations.
 It is crucial that your manipulator return a reference to the invoking
stream. If this is not done, your manipulators cannot be used in a sequence
of input or output operations.
 ‘istream’ and ‘ostream’ are derived from ‘ios’, so ‘ifstream’, ‘ofstream’
and ‘fstream’ also have access to all operations defined by ‘ios’.
 Streams that will be performing both input and output operations must be
declared as objects of type ‘fstream’.
 The ios :: trunk value causes the contents of a preexisting file by the same
name to be destroyed and the file to be truncated to zero length
 When you create an output stream using ‘ofstream’, any preexisting file
with the same name is automatically truncated
 The unformatted I/O is also referred to as ‘raw’ I/O
 The lower level unformatted I/O functions are get () and put ()
 The difference between get () and getline () is that getline () read and
removes the delimiter from the input stream, get () does not
 You can perform random access by using the seekg() and seekp()
functions, which are members of the input and output stream classes.
 A pointer declared as a pointer to a base class can also be used to point to
any class derived from that class.
 You can use a base pointer to point to a derived object, you can access
only those members of the derived objects that were inherited from base.
Annamalai University
5.6) Terminal Exercises
1. ______________consolidate a sequence of several separate I/O operations.
2. A _______________manipulator need is used to perform I/O operations on a
nonstandard design.
3. The 2 types of manipulator that operate on_________________ stream and
__________________stream.
4. An input manipulator receives a reference to the stream on which it was invoked.
TRUE/FALSE.

Page 154
Object Oriented Programming

5. To perform file I/O, you must include the header __________________in your
program.
6. Streams that will be performing both input and output operations must be declared
as objects of the type________________.
7. istream and ostream are derived from ______________.
8. To create an input stream, declare an object of type _______________to create an
output stream.
9. The _______________values causes a file to be opened in binary mode.
10. The ios :: in value specifies that file is capable of output. TRUE/FALSE.
11. The _______________value causes the contents of a preexisting file by the same
name to be destroyed and the file to be truncated to zero length.
12. You can read a byte by using ________________and write a byte using
_______________.
13. A generic function is created using the keyword________________.
14. To create a virtual function, precede the functions declaration with the
keyword________________.

5.7) Supplementary Materials


16. Teach yourself C++, third edition, Herbert Scheldt, Tata McGraw Hill.
17. C++ Templates - The Complete Guide by David Vandevoorde and Nicolai M.
Josuttis

5.8) Assignments
1. Write an assignment on polymorphism.
2. Write note on unformatted I/O operations.

5.9) Reference Books


1. A First Book of C++, From Here to There, Third Edition by Gary J. Bronson
2. The Waite Group's C Programming Using Turbo C++/Book and Disk (The Waite
Group) by Robert Lafore
3. http://www.coronadoenterprises.com/tutorials/cpp/index.html
4. http://www.google.com/Top/Computers/Programming/Languages/C++/FAQs,_H
elp,_and_Tutorials/
5. http://www.newty.de/fpt/index.html
6. http://www.eastcoastgames.com/articles/cppexception.html
Annamalai University
5.10) Learning Activities
1. Write a C++ code to read a text file and display the following information.
Number of lines
Number of words
Number of 3 Letter words.
2. Write a code in C++ to create a manipulator called setup() that sets the field width
to 10, the precision to 4 and the fill character to 2.

Page 155
Object Oriented Programming

5.11) Keywords
Manipulators -A data object that is used with the insertion and extraction operators.
Pointer - A data type that holds the address of a location in memory.
Polymorphism -This means the ability to take more than one form.
Virtual functions -This is a member function that is declared within a base class and
redefined by a derived class.
Generic function - A generic function defines a general set of Operations that
will be applied to various types of data
Template -It is used to create a template that describes what a function will do,
leaving it to the compiler to fill in details as needed.

Annamalai University

Page 156

You might also like