Annamalai University
Annamalai University
Annamalai University
ANNAMALAI UNIVERSITY
DIRECTORATE OF DISTANCE EDUCATION
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
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.
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?
Page 1
Object Oriented Programming
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.
Page 3
Object Oriented Programming
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:
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;
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.
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
EXAMPLE:
Here is a program that contains both c and C++-style comments:
/*
this is a c-like comment.
#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;
}
Annamalai University
class class-name{
//private functions and variables
public:
//public functions and variables
}object-list;
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.
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:
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;
}
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.
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)
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.
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
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++.
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.
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.
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.
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”;
}
int main( )
{
myclass ob;
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.
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.
To understand how one class can inherit another, let’s first begin with an example
that, although simple, illustrates many key features of inheritance.
//Using this base class, here is a derived class that inherits it:
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.
};
Annamalai University
int mul( );
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:
Page 17
Object Oriented Programming
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;
}
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.
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
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
is functionally equivalent to
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( ).
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;
}
Page 21
Object Oriented Programming
1.5) Summary
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
Member functions:
To assign initial value
To deposit an account
To withdraw an amount after checking the balance
To display name and balance.
1.11) Keywords
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
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.
Page 24
Object Oriented Programming
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.
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.
Page 25
Object Oriented Programming
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.
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:
// 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
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().
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:
Page 27
Object Oriented Programming
myclass(int i,intj){n=i;d=j;}
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:
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:
One other important point about friend functions is that a friend function can be friends
with more than one class.
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:
Page 29
Object Oriented Programming
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:
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.
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:
Page 31
Object Oriented Programming
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
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.
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.
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().
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.
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:
int main()
{
int *p;
Page 35
Object Oriented Programming
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.
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
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;
}
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.
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( )
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( ).
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).
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:
#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; }
};
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.
#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.
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.
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.
EXAMPLE
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.
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.5) Summary
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.
Page 45
Object Oriented Programming
2.8) Assignments
1. Write an assignment for friend function.
2. Write an assignment on references with perfect example.
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.
‘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
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;
}
For instance, assuming the class myclass for Example 1, both of these declarations are
valid:
myclass ob(10);
myclass ob[5];
#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.
#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”);
sdate.show();
idate.show();
return 0;
}
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.
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:
Page 51
Object Oriented Programming
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:
/*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
/*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. */
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);
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:
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:
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.
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:
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:
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”;
}
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
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.)
Page 59
Object Oriented Programming
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.
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:
Page 61
Object Oriented Programming
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.
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.
/* Create a pointer to void function with one int parameter and one character parameter.
*/
void (*fp2) (int, char);
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.
Page 63
Object Oriented Programming
only one of the overloaded functions. If it does not, ambiguity will be introduced, causing
a compile-time error.
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.
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.
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.
EXAMPLES:
Annamalai University
1.The following program overloads the + operator relative to the coord class. This class
is used to maintain X, Y coordinates.
class coord {
int x, y; // coordinates values
public:
Page 65
Object Oriented Programming
return temp;
}
int main( )
{
coord o1(10, 10), o2(5, 3), o3;
int x, y;
o3.get_xy(x, y);
cout<<”(o1+o2) x: “<<x<<”, y: ”<<y<<”\n”;
return 0;
}
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.
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:
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.
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
int main( )
{
coord o1(10, 10), o2(5, 3), o3;
int x, y;
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;
o3 = o2 = o1;
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:
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);
return 0;
}
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:
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+ + ( );
};
int main( )
{
coord o1(10, 10);
int x, y;
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.
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:
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:
Page 72
Object Oriented Programming
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.
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:
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);
};
return temp;
}
int main( )
{ Annamalai University
coord o1(10, 10), o2(5, 3), o3;
int x, y;
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.
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:
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);
Page 75
Object Oriented Programming
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;
}
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:
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);
};
int main( )
{
coord o1(10, 10);
int x, y;
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
Page 77
Object Oriented Programming
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.
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.
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;
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;
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;
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;
return 0;
}
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:
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);
};
int main( )
{
arraytype ob;
int i;
// this is OK
for(i=0; i<SIZE; i++)
cout << ob[i] << “ “;
return 0;
}
Annamalai University
In this program, When the statement
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.
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.5) Summary
Page 84
Object Oriented Programming
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.
Page 85
Object Oriented Programming
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.
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
Page 87
Object Oriented Programming
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
};
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.
int main( )
Annamalai University
{
derived ob;
ob.setx(10); //ERROR –now private to derived class
ob.sety(20); //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 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.)
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;
int main( )
{
samp ob(10,20);
// ob.b=99; Error! b is protected and thus private ob.c=30;//OK, c is public
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.
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;
}
As you can see, the constructors are executed in order of derivation and the destructors
are executed in reverse order.
#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.
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:
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++.
#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
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.
/* Here, derived3 inherits both derived1 and derived2. However, only one copy of base is
present.
*/
int main( )
Annamalai University
{
derived3 ob;
Page 99
Object Oriented Programming
return 0;
}
Ob.i = 10;
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.
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
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:
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.
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.
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 :
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 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);
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.
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;
}
Page 104
Object Oriented Programming
hello
%%%%%hello
hello%%%%%
123.234567
123.235%%%
2. The following program shows how to use the C++ I/O format functions to create an
aligned table of numbers:
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
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.
As stated above, the manipulators can occur in the chain of I/O operations. For
example:
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
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.
Page 107
Object Oriented Programming
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.
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:
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:
Page 109
Object Oriented Programming
EXAMPLES:
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;
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;
}
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.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.
12. Teach yourself C++, third edition, HERBERT SCHILDT, Tata Mc Graw Hill
Annamalai University
13. Practical C++ Programming By Steve Oualline
4.8) Assignments
Page 114
Object Oriented Programming
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.
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:
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.
#include<iostream>
using namespace std;
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.
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:
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.
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:
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.
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( ):
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:
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;
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;
if(argc!=2) {
cout<<”Usage : WRITE <filename>\n”;
return 1;
}
if(!out) {
cout<<”Cannot open file .\n”;
return 1;
}
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
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:
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:
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( );
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.
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:
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.
EXAMPLES:
#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;
}
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;
if(argc!=3) {
cout<<”Usage : LOCATE <filename> <loc>\n”;
return 1;
}
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
Name Meaning
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:
Page 130
Object Oriented Programming
#include<iostream.h>
#include<fstream.h>
using namespace std;
if(!in) {
cout<<”Cannot open file.\n”;
return 1;
}
char c;
while(in.get(c)) {
cout<<c;
checkstatus(in);
}
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
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);
};
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
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;
}
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 ¬e(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;
}
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:
class base {
int x;
public:
void setx(int i) { x = i; }
int getx( ) { return x; }
};
int main( )
{
Annamalai University
base *p; // pointer to base type
base b_ob; //object of base
derived d_ob; //object of derived
Page 135
Object Oriented Programming
return 0;
}
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:
class base {
public:
int i;
base(int x) { i = x; }
virtual void func( )
{
cout << “Using base version of func( ) : “;
cout << 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;
}
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
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:
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 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.
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.
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:
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.
temp = a;
a = b;
b = temp;
}
int main( )
{ Annamalai University
int i=10, j=20;
float x=10.1, y=23.3;
Page 141
Object Oriented Programming
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.
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:
Here type is the name of the data that the class will be operating upon.
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.
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;
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:
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.
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);
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.)
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.
EXAMPLE:
1. Here is a simple example that shows the way C++ exception handling operators:
int main( )
{
Annamalai University
cout<< “Start \n”;
Page 146
Object Oriented Programming
cout<<”End”;
return 0;
}
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:
int main( )
{ Annamalai University
cout<<”Start\n”;
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;
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;
}
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;
}
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;
Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
cout << “end”;
return 0;
}
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
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
}
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:
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.
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.
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.
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;
}
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.
Page 153
Object Oriented Programming
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.8) Assignments
1. Write an assignment on polymorphism.
2. Write note on unformatted I/O operations.
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