Professional Documents
Culture Documents
1.1 Introduction
● The mechanism of giving special meanings to an operator for a data type is known
as operator overloading.
● It allows extending functionality of an existing operator to operate on user defined
data type.
● The operator such as +,-,+=,>,>> etc., are designed to operate only on standard
data types in structure oriented programming like C.
● The + operator can be used to perform the addition operation on integer, floating
point or mixed data types as indicated in the expression(a+b).
● In this expression, the data type of the operand a and b on which the + operator is
operating, is not mentioned explicitly.
● In such cases, the compiler implicitly selects suitable addition operation depending
on the data type of operands without any assistance from the programmer.
● In C++, such operator can also be overloaded explicitly to operate on operands of
user defined data types.
● For instance, the statement
C3=AddComplex(c1,c2);
Performs the addition of operand c1 and c2 belonging to the user defined data type
and assign the result to c3.
● In C++, by overloading operator, the above statement can be changed to an easily
readable form:
C3 = c1 + c2;
● Operator overloading, thus allows to provide additional meaning to operator such
as +,*,>=,+=, etc., when they are applied to user defined data types.
● It allows the user to program (develop solution to) the problems as perceived in the
real world.
● The concept of operator overloading can also be applied to data conversion. C++
offers automatic conversion of primitive data types.
● Operator overloading extends the semantics of an operator without changing its
syntax. The grammatical rules defined by C++ that governs its use such as the
UNIT-4 OOP USING C++ Page 2 of 29
● Assume that array is a class and following are valid operator function.
● friend void operator +( array &t) { … } //Unary plus with friend, array is a class
● array operator + () {…} //Unary plus, that return an object of a class array
● friend void operator + (array &t1, array &t2){…} //Binary plus with friend
Arithmetic +, - , *, /, %
Bit-wise &, |, ~, ^
Logical &&, ||, !
Relational >, <, ==, !=, <=, >=
Assignment =
Arithmetic assignment +=, -=, *=, /=, %=, &=, |=, ^=
Shift <<, >>, <<=, >>=
Unary ++, --
Subscripting []
Function call ()
Dereferencing ->
Unary Sign prefix +, -
Memory allocate and Free new, delete
● Program: Consider an example of class Index that keeps track of the index value
without using overloaded concept.
#include<iostream.h>
#include<conio.h>
class Index
{
private:
int value;
public:
Index();
void print( );
void nextIndex( );
};
Index :: Index ( )
{
value = 0;
}
void Index :: print ( )
{
cout<<value;
}
void Index :: nextIndex ( )
{
value = value + 1;
}
void main ( )
UNIT-4 OOP USING C++ Page 5 of 29
{
Index i1;
clrscr ( );
cout<<”Value of i1.value=”;
i1.print();
i1.nextIndex( );
cout<<”After function nextIndex() call, Value of i1.value=”;
i1.print();
getch();
}
Output:
Value of i1.value=0
After function nextIndex() call, Value of i1.value=1
● In above program, the function nextIndex() increments the index value. Now, the
function nextIndex() is replaced by operator ++ function using operator overloading
concept. The above program can be rewritten using overloaded increment operator
as follow.
● Program: Consider an example of class Index that keeps track of the index value
with using overloaded concept. (using increment operator)
#include<iostream.h>
#include<conio.h>
class Index
{
private:
int value;
public:
Index();
void print( );
void operator ++ ( );
};
Index :: Index ( )
{
value = 0;
}
void Index :: print ( )
{
cout<<value;
}
void Index :: operator ++ ( )
UNIT-4 OOP USING C++ Page 6 of 29
{
value = value + 1;
}
void main ( )
{
Index i1;
clrscr ( );
cout<<”Value of i1.value=”;
i1.print();
i1++; // It is equivalent to i1.operator++();
cout<<”After increment, Value of i1.value=”;
i1.print();
getch();
}
Output:
Value of i1.value=0
After increment, Value of i1.value=1
● In main(), the statement
o i1++ ;
● call the overloaded ++ operator member function defined in the class Index:
o void operator ++ ( )
● The unary increment/decrement operator can be prefix or postfix increment. It
means above program we may write ++i1; instead of i1++; In the both the
increment, output of the program is same.
● In above program, another way of writing operator++() function is that return data
type is name of a class instead of void.
[1]. Return data type is void [2]. Return data type is class itself
i1.print();
i2 = i1++;
cout<<”After increment, Value of i2.value=”;
i2.print();
getch();
}
● In main() function, the statement
i2 = i1++;
● calls the overloaded operator function and assigns the return value to the object i2
of the class Index. The operator ++() function creates a new object of the class
Index called temp to be used as a return value; it can be assigned to another object
(i2).
class test
{
public:
int a;
test operator+(test &t);
};
test test :: operator+(test &t)
{
test temp;
temp.a = a + t.a;
return temp;
}
void main()
{
UNIT-4 OOP USING C++ Page 8 of 29
test t1,t2,t3;
clrscr();
cout<<"Enter a for object t1 = ";
cin>>t1.a;
cout<<"Enter a for object t2 = ";
cin>>t2.a;
t3 = t1 + t2;
cout<<endl<<"For t1 object Value of a = "<<t1.a;
cout<<endl<<"For t2 object Value of a = "<<t2.a;
cout<<endl<<"Value Sum of t1 and t2 object = "<<t3.a;
getch();
}
Output:
Enter a for object t1 = 2
Enter a for object t2 = 3
For t1 object value of a = 2
For t2 object value of a = 3
Value sum of t1 and t2 object = 5
● The friend function outside the body of a class is defined as a normal function
without prefix friend keyword.
● Friend functions can either be used with unary (One Argument) or binary operators
(Two Arguments).
● Friend function is not allowed to access members of a class (to which it is defined)
directly, but it can access all the members including the private members by using
object of that class.
● The difference between friend and member function is that, the friend function
requires the arguments to be explicitly passed to the function and processed them
explicitly whereas member function consider the first argument implicitly.
class Index
{
private:
int value;
public:
Index();
void print( );
friend void operator ++ (Index &t );
};
Index :: Index ( )
{
value = 0;
}
void Index :: print ( )
{
cout<<value;
}
void operator ++ (Index &t )
{
t.value = t.value + 1;
}
void main ( )
{
Index i1;
clrscr ( );
cout<<”Value of i1.value=”;
i1.print();
i1++; // It is equivalent to i1.operator++();
cout<<”After increment, Value of i1.value=”;
i1.print();
getch();
}
Output:
Value of i1.value=0
After increment, Value of i1.value=1
● //Program based on Binary operator overloading using friend function.
#include<iostream.h>
#include<conio.h>
class test
{
public:
int a;
friend test operator+(test &t1, test &t2);
};
UNIT-4 OOP USING C++ Page 10 of 29
● There are some rules for writing overloading operator. They are
1. Only existing operators can be overloaded. New operators cannot be created.
2. The overloaded operator must have at least one operand that is of user defined
type.
3. We can not change the basic meaning of an operator. That is to say, we can not
redefine the plus (+) operator to subtract one value from the other.
4. Overloaded operator follow the syntax rules of the original operators. They cannot
be overridden.
5. There are some operators that cannot be overloaded. (On Page No. 2)
6. We cannot use friend function to overloaded certain operators. However, member
function can be used them. (On Page No. 2)
7. Unary operator overloaded through a member function with no argument and those
which are overloaded through a friend function with one argument.
UNIT-4 OOP USING C++ Page 11 of 29
8. Binary operator overloaded through a member function with one argument and
those which are overloaded through a friend function with two arguments.
GENERAL FORM :-
Data type *pt_names;
● This will declares the variables p as a pointer variable that points to an integer data
type.
Float *x;
● declares x as a pointer to a floating point variable.
P =&quantity;
● It means now p contain the address of quantity
Float a, b ;
int x, *p;
p= &a;
b= *p;
● This will result in erroneous output because we trying to assign the address of a
float variable to an integer pointer.
● The compiler will not detect such errors, care should be taken by the programmer.
int *ptr;
ptr= 5368;
● Assigning an absolute address to a pointer variable is invalid. A pointer variable
can be initialized in its declaration itself.
UNIT-4 OOP USING C++ Page 12 of 29
void main( )
{
int x , y;
int *ptr ;
x =10;
ptr = &x;
y =*ptr;
*ptr = 25;
printf(“ \n Now X= %d \n “,x);
}
output:-
value of x is 10
10 is stored at addr 4104
10 is stored at addr 4104
10 is stored at addr 4104
10 is stored at addr 4104
4104 is stored at addr 4106
10 is stored at addr 4108
now x=25
● If p1 and p2 are properly declared and initialized pointers then, the following
statements are valid.
Y= *p1 * *p2;
Same as (*p1) * (*p2)
Sum=sum + *p1;
Z= 5*- *p2/*p1;
UNIT-4 OOP USING C++ Page 13 of 29
Same as (5 *(-(*p2)))/(*p1)
*p2 = *p2 + 10;
● ‘c’ and ‘c++’ allows us to add integers to or subtract integers from pointers, as well
as to subtract one pointer from another.
P1 + 4, p2 – 2 and p1- p2
● We may also short-hand operators with the pointers.
P1+ +;
- - p2;
sum + =*p2;
x = *p1 * *p2 – 6;
y = 4* - *p2 / *p1 + 10;
printf(“Address of a= %u \n”,p1);
printf(“Address of b= %u \n”,p2);
printf(“ a= %d b = %d \n” ,a ,b);
printf(“ x= %d y =%d \n” ,x ,y);
*p2 = *p2 + 3 ;
*p1 = *p2 – 5;
z= *p1 * *p2- 6;
printf(“ a= %d b = %d ” ,a ,b);
printf(“ z= %d \n” ,z);
}
output:-
Address of a = 4020
Address of a = 4016
a = 12, b = 4
UNIT-4 OOP USING C++ Page 14 of 29
x = 42, y = 9
a = 2, b =7, z=8
The array err holds pointers to each string. As you can see, printf( ) inside
syntax_error( ) is called with a character pointer that points to one of the various
error messages indexed by the error number passed to the function. For example,
if num is passed a 2, the message Write Error is displayed.
objects. When accessing members of a class given a pointer to an object, use the arrow
(–>) operator instead of the dot operator. The next program illustrates how to access an
object given a pointer to it:
#include <iostream.h>
class cl {
int i;
public:
cl(int j) { i=j; }
int get_i() { return i; }
};
int main()
{
cl ob(88), *p;
p = &ob; // get address of ob
cout << p->get_i(); // use -> to call get_i()
return 0;
}
As you know, when a pointer is incremented, it points to the next element of its type.
For example, an integer pointer will point to the next integer. In general, all pointer
arithmetic is relative to the base type of the pointer. (That is, it is relative to the type of
data that the pointer is declared as pointing to.) The same is true of pointers to objects.
For example, this program uses a pointer to access all three elements of array ob after
being assigned ob's starting address:
#include <iostream.h>
class cl {
int i;
public:
cl() { i=0; }
cl(int j) { i=j; }
int get_i() { return i; }
};
int main()
{
cl ob[3] = {1, 2, 3};
cl *p;
int i;
p = ob; // get start of array
for(i=0; i<3; i++) {
cout << p->get_i() << "\n";
p++; // point to next object
}
return 0;
}
UNIT-4 OOP USING C++ Page 16 of 29
You can assign the address of a public member of an object to a pointer and then access
that member by using the pointer. For example, this is a valid C++ program
that displays the number 1 on the screen:
#include <iostream.h>
class cl {
public:
int i;
cl(int j) { i=j; }
};
int main()
{
cl ob(1);
int *p;
p = &ob.i; // get address of ob.i
cout << *p; // access ob.i via p
return 0;
}
Here, p_var is a pointer variable that receives a pointer to memory that is large enough to
hold an item of type type.Since the heap is finite, it can become exhausted. If there is
insufficient available memory to fill an allocation request, then new will fail and a
bad_alloc exception will be generated. This exception is defined in the header <new>.
Your program should handle this exception and take appropriate action if a failure occurs.
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.
#include <iostream.h>
void main()
{
int *p;
p = new int; // allocate space for an int
*p = 100;
UNIT-4 OOP USING C++ Page 17 of 29
This program assigns to p an address in the heap that is large enough to hold an
integer. It then assigns that memory the value 100 and displays the contents of the
memory on the screen.
The delete operator must be used only with a valid pointer previously allocated by
using new. Using any other type of pointer with delete is undefined and will almost
certainly cause serious problems, such as a system crash. 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 the sizeof operator. Because the size is computed
automatically, it eliminates any possibility for error in this regard.
● Second, new automatically returns a pointer of the specified type. You don't need
to use an explicit type cast as you do when allocating memory by using malloc( ).
Finally, both new and delete can be overloaded, allowing you to create customized
allocation systems.
You can initialize allocated memory to some known value by putting an initializer
after the type name in the new statement. Here is the general form of new when an
initialization is included:
p_var = new var_type (initializer);
Of course, the type of the initializer must be compatible with the type of data for which
memory is being allocated.
This program gives the allocated integer an initial value of 87:
#include <iostream.h>
int main()
{
int *p;
p = new int (87); // initialize to 87
cout << "At " << p << " ";
cout << "is the value " << *p << "\n";
delete p;
return 0;
}
Allocating Arrays
You can allocate arrays using new by using this general form:
p_var = new array_type [size];
Here, size specifies the number of elements in the array. To free an array, use this form of
delete:
delete [ ] p_var;
Here, the [ ] informs delete that an array is being released.
For example, the next program allocates a 10-element integer array.
#include <iostream.h>
int main()
{
int *p, i;
UNIT-4 OOP USING C++ Page 18 of 29
Here is a short program that creates a class called balance that links a person's
name with his or her account balance. Inside main( ), an object of type balance is
created dynamically.
#include <iostream.h>
#include <cstring.h>
class balance {
double cur_bal;
char name[80];
public:
void set(double n, char *s) {
cur_bal = n;
strcpy(name, s);
}
void get_bal(double &n, char *s) {
n = cur_bal;
strcpy(s, name);
}
};
int main()
{
balance *p;
char s[80];
double n;
p = new balance;
p->set(12387.87, "Ralph Wilson");
p->get_bal(n, s);
cout << s << "'s balance is: " << n;
cout << "\n";
delete p;
return 0;
UNIT-4 OOP USING C++ Page 19 of 29
Because p contains a pointer to an object, the arrow operator is used to access members
of the object. As stated, dynamically allocated objects may have constructors and
destructors. Also, the constructors can be parameterized. Examine this version of the
previous program:
#include <iostream.h>
#include <cstring.h>
class balance {
double cur_bal;
char name[80];
public:
balance(double n, char *s) {
cur_bal = n;
strcpy(name, s);
}
~balance() {
cout << "Destructing ";
cout << name << "\n";
}
void get_bal(double &n, char *s) {
n = cur_bal;
strcpy(s, name);
}
};
int main()
{
balance *p;
char s[80];
double n;
// this version uses an initializer
p = new balance (12387.87, "Ralph Wilson");
p->get_bal(n, s);
cout << s << "'s balance is: " << n;
cout << "\n";
delete p;
return 0;
}
Notice that the parameters to the object's constructor are specified after the type name,
just as in other sorts of initializations.
You can allocate arrays of objects, but there is one catch. Since no array allocated by new
can have an initializer, you must make sure that if the class contains constructors, one will
be parameterless. If you don't, the C++ compiler will not find a matching constructor when
you attempt to allocate the array and will not compile your program. In this version of the
preceding program, an array of balance objects is allocated, and the parameterless
constructor is called.
#include <iostream.h>
#include <cstring.h>
class balance {
double cur_bal;
char name[80];
public:
UNIT-4 OOP USING C++ Page 20 of 29
One reason that you need to use the delete [ ] form when deleting an array of
dynamically allocated objects is so that the destructor can be called for each object
in the array.
UNIT-4 OOP USING C++ Page 21 of 29
▪
Data files are attached with files objects using the open() member function of the file
object.
▪ The open() prototype is:
void open(const char *name, int mode, int access);
▪ Where:
1. name is the filename.
2. Open file modes (flags) are used to indicate what to do to the file (e.g. open,
close) and the data (e.g. read, write). The flags can be logically ORed. Mode
must be one of the following:
3. File protection [Table: File open modes]
Mode Description
ios::app Append data to the end of the output file.
ios::ate Go to the end of the file when open.
ios::in Open for input, with open() member function of the ifstream variable.
ios::out Open for output, with open() member function of the ofstream
variable.
ios::binary Binary file, if not present, the file is opened as an ASCII file as
UNIT-4 OOP USING C++ Page 22 of 29
default.
ios::trunc Discard contents of existing file when opening for write.
ios::nocreate Fail if the file does not exist. For output file only, opening an input file
always fails if there is no fail.
ios::noreplace Do not overwrite existing file. If a file exists, cause the opening file to
fail.
4. File protection access determines how the file can be accessed. It is Operating
System dependent and there are others attributes that are implementation
extensions. For DOS example, it must be one of the following:
Attributes Description
0 Normal file or Archive
1 Read-only file
2 Hidden file
4 System file
[Table: File types]
▪ To declare the input file stream i.e. for reading we would declare like this:
ifstream theinputfile;
▪ To declare the output file stream i.e. for writing we would declare like this:
ofstream theoutputfile;
▪ Then, to connect to a stream, let say opening file testfileio.dat for reading, the file
which located in the same folder as the executable program we would write like
this:
theinputfile.open("testfileio.dat ");
▪ Or with the path we could write:
theinputfile.open("c:\\testfileio.dat ");
▪ Next, opening a file for reading and binary type modes, we could write:
theinputfile.open("testfileio.dat ", ios::in | ios::binary);
▪ Another example, opening a file for reading, with normal type access and go to the
end of the file, we could write like this:
theinputfile.open("testfileio.dat ", ios::in | ios::ate, 0);
▪ For writing, to connect to a stream, let say opening file testfileio.dat for writing, the
file which located in the same folder as the running program. Previous content of
the testfileio.dat will be overwritten, we could write like this:
theoutputfile.open("testfileio.dat");
▪ Or with the path:
theoutputfile.open("c:\\testfileio.dat ");
▪ Then, opening a file for writing and appending at the end of the file modes, we
could write like this:
theoutputfile.open("testfileio.dat", ios::out | ios::app);
▪ Or opening for writing, check the existing of the file with normal access modes, we
could write like this:
theoutputfile.open("testfileio.dat", ios::out | ios::nocreate, 0);
▪ After we have completed the file processing, we have to close or disconnect the
stream to free up the resources to be used by other processes or programs. Using
the close() member function, for input stream we would write like this:
UNIT-4 OOP USING C++ Page 23 of 29
theinputfile.close();
▪ And for output stream:
theoutputfile.close();
UNIT-4 OOP USING C++ Page 24 of 29
● good() : It is the most generic state flag: it returns false in the same cases in which
calling any of the previous functions would return true.
void main(void)
{
ifstream inputfile;
inputfile.open("testfileio.dat");
if(inputfile.fail())
{
cout<<"The file could not be opened!\n";
exit(1); // 0 – normal exit, non zero – some error
}
...
}
Or bad() with cerr.
if(inputfile.bad())
{
cerr<<"Unable to open testfileio.dat\n";
exit(1); // 0 – normal exit, non zero – some error
}
In order to reset the state flags checked by any of these member functions we have just
seen we can use the member function clear(), which takes no parameters.
seekg ( position );
seekp ( position );
Using this prototype the stream pointer is changed to the absolute position position
(counting from the beginning of the file). The type for this parameter is the same as the
one returned by functions tellg and tellp: the member type pos_type, which is an integer
value.
Using this prototype, the position of the get or put pointer is set to an offset value relative
to some specific point determined by the parameter direction. offset is of the member type
off_type, which is also an integer type. And direction is of type seekdir, which is an
enumerated type (enum) that determines the point from where offset is counted from, and
that can take any of the following values:
ios::b
offset counted from the beginning of the stream
eg
ios::cu offset counted from the current position of the stream
r pointer
ios::e
offset counted from the end of the stream
nd
The following example uses the member functions we have just seen to obtain the size of
a file:
obtaining file size
#include <iostream.h>
#include <fstream.h>
int main () {
long begin,end;
ifstream myfile ("example.txt");
Ouput:
begin = myfile.tellg();
size is: 40
myfile.seekg (0, ios::end);
bytes.
end = myfile.tellg();
myfile.close();
cout << "size is: " << (end-begin) << " bytes.\
n";
return 0;
}
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. For example, this program creates a short
inventory file that contains each item's name and its cost:
#include <iostream.h>
#include <fstream.h>
int main()
{
ofstream out("INVNTRY"); // output, normal file
if(!out) {
cout << "Cannot open INVENTORY file.\n";
return 1;
}
out << "Radios " << 39.95 << endl;
out << "Toasters " << 19.95 << endl;
out << "Mixers " << 24.80 << endl;
out.close();
return 0;
}
The following program reads the inventory file created by the previous program
and displays its contents on the screen:
#include <iostream.h>
#include <fstream.h>
int main()
{
ifstream in("INVNTRY"); // input
if(!in) {
cout << "Cannot open INVENTORY file.\n";
return 1;
}
char item[20];
float cost;
in >> item >> cost;
cout << item << " " << cost << "\n";
in >> item >> cost;
cout << item << " " << cost << "\n";
in >> item >> cost;
cout << item << " " << cost << "\n";
in.close();
return 0;
}
All information is stored in the file in the same format as it would be displayed on
the screen while use the >> and << operator for reading from and writing to files.
Following is another example of disk I/O. This program reads strings entered at the
keyboard and writes them to disk. The program stops when the user enters
an exclamation point. To use the program, specify the name of the output file on the
command line.
#include <iostream.h>
#include <fstream.h>
UNIT-4 OOP USING C++ Page 27 of 29
Here we first define a pointer string and the integer type size variable to store the sizew of
the file. Then with the help of ifstream we open the file file.txt in binary read mode and
place the cursore at the end of file with the help of ios::binary|ios:ate
Then we open the another file in binary in which we want to place the data in output mode
defined as ios::binary
size=infile.tellg();
buffer = new char[size];
with tellg() functiojn we get the size of the file and define the buffer variable of that size.
infile.seekg(0);
infile.read(buffer,size);
infile.close();
As in the opened input fil, the cursor at the end of file, now we have to manually move it
beginning of file, then read the data and store it to buffer and then close the file.
outfile.write(buffer,size);
outfile.close();
Now, we write the data in the another file that is open in the output format, and then close
that file.
● When the file is closed: before closing a file all buffers that have not yet been
flushed are synchronized and all pending data is written or read to the physical
medium.
● When the buffer is full: Buffers have a certain size. When the buffer is full it is
automatically synchronized.
● Explicitly, with manipulators: When certain manipulators are used on streams,
an explicit synchronization takes place. These manipulators are: flush and endl.
UNIT-4 OOP USING C++ Page 29 of 29