You are on page 1of 24

 

 C++ Tutorials  >  Object Oriented Programming  >  Introduction to Object Oriented
Programming
 
Introduction to the Object-oriented Approach

The fundamental idea behind an object-oriented language is to combine both data and the
functions that operate on the data into a single unit. Such a unit is called an object.

Data members of an object can be accessed only by using the functions of the object.
Therefore, the data is hidden and is safe from accidental alteration. Data and functions are
stored into a single entity.

The functions of an object are called the member functions. These member functions are
called method in other object-oriented languages like Small Talk.

Introduction to the Object-oriented Approach

Figure 10.1 shows the components of an object in C++.

Figure 10.1 Componets of an Object


 Characteristics of an Object-oriented Language

The important elements of an object-oriented language are:

Class

An Object in C++ is an instance of a class. For example, in the following statement:

int iNum1, iNum2, iNum3;

iNum1, iNum2, iNum3 are three variables of type int.


Similarly, you can define many objects of the same class as shown in Figure 10.2

 
Fig 10.2 Class and Objects of the Class

Inheritance

Inheritance is the process of creating a new class, called the derived class, from the existing
class, called the base class.

Figure 10.3 shows the inheritence of a derived class from the base class.

 
Figure 10.3 Inheritance of a Derived Class From a Base Class

For example, motorcycles, cars and trucks have certain common properties-- all have wheels,
engines and breaks. Therefore, they can be grouped under a class called automobiles. Apart
from sharing these common features, each subclass has its own particular characteristices--
cars use petrol while trucks use diesel.

The derived class has its own characteristics and, in addition, inherits the
properties of the base class.

Reusability

The concept of inheritence provides an important feature to the object-oriented lanuage-


reusability. A programmer can take an existing class and, without modifyinh it, and additional
features and capabilities to it. This is done by deriving a new class from an existing class.

Polymorphism

The word polymorphism is derived from two Latin words poly (many) and morphos
(forms). The concept of using operators or functions in different ways, depending on what
they are operating on, is called polymorphism.

The following program uses an overloaded function to illustrate polymorphism:

//This program uses an overloaded function to display a character or an integer


#include<iostream.h>
void disp(int);
void disp(char);
void main()
{
disp(10);
disp(‘a’);
}
void disp(int iNum1)
{
cout<<”The number is”<<iNum1<<endl;
}
void disp(char cCh)
{
cout<<”The character is”<<oCh<<endl;
}

The output of Program 10.1 is:

The number is 10
The character is a

In Program 10.1, the function disp() is overloaded and, based on the parameter passes, the
corresponding message is displayed, therefore exhibiting polymorphism.

A Sample Program

The following program illustrates the usage of objects and classes in C++:
//The program uses member functions to input two numbers, add two numbers and display the result
#include<iostream.h>
class add //Specifies the class
{
private:
int iNum1, iNum2, iNum3; //Member data
public:
void input(int iVar1, int iVar2) //Member function
{
cout<<”Functions to assign values to the member data”<<endl;
iNum1=iVar1;
iNum2=iVar2;
}
void sum(void) //Member function
{
cout<<”Functions to find the sum of two numbers”<<endl;
iNum3=iNum1+iNum2;
}
void disp(void) //Member function
{
cout<<”The sum of the two numbers is”<<iNum3<<endl;
}
};

void main()
{
add A1;
int iX, iY;
cout<<”Input two numbers”<<endl;
cin>>iX;
cin>>iY;
A1.input(iX, iY);
A1.sum();
A1.disp();
}

The sample output of Program 10.2 is:


Input two number
3
2
Function to assign values to the member data
Function to find the sum of two numbers
The sum of the two numbers is 5

Class Specifier
The specifier for a class starts with the keyword class followed by the class name. In Program 10.2, the
class specifier is:
Class add
{
private:
int iNum1, iNum2, iNum3; Member data
};
As in the case of a structure, the body of the class is delimited by braces and is terminated by a
semicolon.

Defining the Object

In Program 10.2, the statement:


Add A1;
defines an object A1, which is an instance of a class called add. It is this definition that actually creates
objects and allocates memory for them.

Access Specifiers

The body of the class contains two keywords:


• Private
• Public

The keywords private and public are called access specifiers. The primary mechanism used to
incorporate data hiding in C++ is by using the private keyword. Private data or functions can only be
accesses from within the class. Public data or functions, on the other hand, are accessible outside the
class. This is shown in Figure 10.4

Therefore, in Program 10.2, it is not possible to access the member data iNum1, iNum2 and iNum3
directly from function main() as they are private o the add class. This data can be accessed only from
the member functions of that class.

Usually the data within the class is declared as private and the functions are declared as public.
Therefore, the data is hidden and safe from accidental manipulation, whereas functions that operate
on this data can be accessed from outside the class. The outcome of abstracting the internal
implementation of a class with the use of access specifiers produces what is known as Abstract Data
Type.

Invoking Member Functions

In Program 10.2, the statements:


Add A1;
A1.input(ix, iy);
A1.sum();
A1.disp();

Are used to invoke the member functions of the class add :

The dot operator, also called the class member access operator, is used to associate the object name
with the member function.

In Program 10.2 the dot operator associates the object A1 with the function input(), sum() and disp().

Scope Resolution Operator

In Program 10.2, the member functions are defined within the class specifier. These functions can also
be defined outside the boundaries of the class using the scope resolution operator(::).

Program 10.2 can be modified using the scope resolution operator in the following way:

//This program uses the scope resolution operator to define the functions outside the class
#include<iostream.h>
class add
{
private:
int iNum1, iNum, iNum3;
public:
void input(int, int);
void sum(void);
void disp(void);
};
void add::input(int iVar1, int iVar2)
{
iNum1=iVar1;
iNum2=iVar2;
}
void add::sum(void)
{
iNum3=iNum1+iNum2;
}
void add:disp(void)
{
cout<<”The sum of two numbers is”<<iNum3<<endl;
}
void main()
{
add A1;
int iX, iY;
cout<<”Input two numbers”<<endl;
cin>>iX;
cin>>iY;
A1.input(iX, iY);
A1.sum();
A1.disp();
}

The member functions of the class add are defined outside the class using the scope resolution
operators (::). In Program 10.3, the statement:
Void add::input(int iVar1, int iVar2)

uses the scope resolution operator to define the function outside the boundary of the class.

In the above statement, void is the return type of the function, add is the class name, :: is the scope
resolution operator, input is the function name, and int iVar1 and int iVar2 are the function
parameters.

The declaration:
Void input(int, int);
in the class informs the compiler that this function is a member of the class but will be defined
outside the class.
 Structures vs. Classes

The only difference between a structure and a class is that, in a class, the member data or function
are private by default whereas, in a structure, they are public by default.

The following code segment:


Class demo
{
private:
int iNum1;
public:
void func(void);
};

can be written as:

class demo
{
int iNum1;
public:
void func(void);
};

The keyword private need not be mentioned because, in a class, the members are private by default.
The code segment can be modified using a structure in the following way:

Class demo
{
int iNum1;
public:
void func(void);
};
The keyword private need not be mentioned because, in a class, the members are private by default.

The code segment can be modified using a structure in the following way:
struct demo
{
void func(void);
private:
int iNum1;
};
The keyword public need not be mentioned because the structure members are public by default.

Constructors

Every object created would have a copy of data members, which require initialization before they can
be used. In the example discussed earlier, the object A1 of class add had to call a member function
called input() to initialize the member data iNum1 and iNum2. In this case, there is no possibility of
member data getting initialized automatically whenever an object is created. Since this requirement is
so common, C++ allows objects to initialize themselves as and when they are created. This automatic
initialization is performed through the use of constructor functions.

Declaration of Constructors

A constructor function is a special function that is a member of the class and has the same name as
that of the class. For example, the following code shows the add class when it is written to use a
constructor function for initialization:
Class add
{
private:
int iNum1, iNum2,iNum43;
public:
add(); //Constructor
void input(int, int);
void sum(void);
void disp(void);
};
Notice that the constructor add() had no return type specified. In C++, constructors cannot return
values.

The add() function can be coded in the following way:


add::add()
{
iNum1=iNum2=iNum3=0;
cout<<”Constructor Invoked”<<endl;
}

The message “Constructor Invoked” is the output to illustrate that the constructor is being called. In
actual practice, constructors are used only for initialization and are not used for any input or output
operations.
If no constructors are declared for a class, the compiler invokes its own constructor.

Overloading Constructors

Besides performing the special role of initialization, constructors are no different from other
functions. This includes overloading also. It is very common to find overloaded constructors. For
example, consider the following program with overloaded constructors for the add class:

//Program to illustrate the application of add class


#include<iostream.h>
class add
{
private:
int iNum1, iNum2, iNum3;
public:
add(void); //Default construcors
add(int, int) //Two-Argument Constructor
void input(int, int);
void sum(void);
void disp(void);
};
add:add(void) //Default constructor
{
iNum1=iNum2=iNum3=0;
}
add:add(int iX, int iY) //Constructor 2
{
iNum1=iX;
iNum2=iY;
iNum3=0;
}
void add::input(int iVar1, int iVar2)
{
iNum1=iVar1;
iNum2=iVar2;
}
void add::sum(void)
{
iNum3=iNum1+iNum2;
}
void add::disp(void)
{
cout<<”The sum of two numbers is”<<iNum3<<endl;
}
void main()
{
add A1; //Default constructor invoked
add A2(4,3); //Constructor 2 invoked
add *Aptr;
Aptr=new add(5,10); //Pointer is initialized with address
//and values assigned to member data
A2.sum(); //sum() function invoked to initialize
//member data
Aptr->sum();
Aptr->disp(); //disp() function invoked to display
//the value of member data
A2.disp();
}

Here, for the object A1, the constructor with no argument, also called the default constructor, will be
invoked because A1 is created with no arguments. But, for the object A2 and the pointer Aptr, the-
two argument constructor will get invoked because they are created with two arguments. The
conclusion that follows is that a class can have many constructors each differing in the number, type
and order of arguments. The number. Type and order of arguments are together referred to as the
signature of the function.

Destructors

Destructors are functions that are complimentary to constructors. They de-initialize objects when
they are destroyed. A destructor is invoked when an object of the class goes out of scope, or when
the memory occupied by it is deallocated using the delete operator.

Declaration of Destructors

A destructor is a function that has the same name as that of the class but is prefixed with a ~(tilde).
Overloading a destructor is not possible. It can be explicitly invoked. In other words, a class can have
only one destructor. A destructor cannot take arguments or specify a return value, or explicitly return
a value.

The following code segment depicts the add class after the inclusion of a destructor:

Class add
{
private:
int iNum1, iNum2, iNum3;
public:
add(int=0; int=0); //Default Argument Constructor, to reduce the number of constructors
void input(int,int);
void sum(void);
~add(void); //Destructor
};

add::~add(void)
{
iNum1 = iNum2 = iNum3 = 0;
}

add::add(int iX = 0, int iY = 0)
{
iNum1 = iX;
iNum2 = iY;
iNum3 = 0;
}

void add::input(int iVar1, int iVar2)


{
iNum1 = iVar1;
iNum2 = iVar2;
}

void add::sum(void)
{
iNum13 = iNum1 + iNum2;
}

void add::disp(void)
{
cout<<”The sum of two numbers is”<<iNum3<<endl;
}

To explicitly call a destructor for an object, the following notation is used:


<object>-><class name>::<destructor>;

The following code explicitly invokes the destructor:


Add *Aptr;
Aptr = new add; //Default constructor
Aptr->add::~add(); //Explictly invoking the destructor

Binding

Object-oriented programming implements the concept of generalization through inheritance. A


related feature offered by C++ is late binding. This session focuses on this feature and how it
can be used to make the code of your program less complex and easier to maintain.

Concept of Binding
Consider a class hierarchy to represent the family of personal computers. The PC class is the
base class from which the PC_XT class is derived. The PC_XT class in turn is the base class
for PC_AT class. Figure 16.1 represents the class hierarchy.

 
Fig 16.1 PC Class Hierarchy

Consider the following statements:


PC_XT Busybee;
Busybee.get_ram_space();

An object of the PC_XT class named Busybee is created and a member function called
get_ram_space() is invoked. To invoke the function get_ram_space(), the compiler should
know the class to which this function belongs. In this compiler will know that the function
get_ram_space() of the PC_XT class is being referred. Any member function of a class can be
invoked from the instance of that class. In the following statement:

PC *Ptr;
….
….
Ptr->get_ram_space();

The compiler needs to associate the get_ram_space() function with a particular class. Here
again, there is no ambiguity. The compiler associates the function with the PC class, based on
the pointer Ptr. Thus, the compiler associates the function with the class by identifying the
type of the object or pointer that is used to invoke the function. This process of associating a
function to an object or pointer is called binding.

In certain programming situations, the type of the object or pointer may not be known at the
time of compilation. For example, there may be a requirement where a list of personal
computers needs to be created. Depending on the request of the user, the properties of a
particular computer, such as CPU speed, hard disk capacity, memory space etc, may have to
be displayed. Since the objects are dynamically created, the type of the object is not known
during compile time. In these situations, the binding of the function to the class is done during
run-time. This process is called dynamic binding or late binding.

In C++, there exists a special relationship between the base class and the derived class. A
pointer to a base class object can point to an object of any of the derived class. A pointer to a
base class object can point to an object of any of the derived classes. For example, the PC
class in the PC family can point to an object of the PC, PC_XT or PC_AT class. Thus, the
following assignments are valid:
PC *Ptr;
Ptr = new PC_XT;
Ptr = new PC_AT;

Virtual Functions

While pointers are necessary for late binding, they are not sufficient to implement it.

Consider the following statements:

PC *Ptr;
Ptr = new PC_XT;
Ptr->get_ram_space();

The compiler always invokes the member function of the PC class although Ptr is pointing to an object
of the PC_XT class. This happens because, binding takes place at the time of compilation, when the
content of the pointer is not known. Thus, base class pointers alone are not sufficient to implement
late binding.

To ensure late binding, the concept of virtual function needs to be understood. A virtual function is a
function that is declared as virtual in a base class and is redefined by a derived class. A function is
declared virtual because its execution depends on the contents of the base class pointer used to
invoke it, which is not known at the time of compilation. To declare a function as virtual, its
declaration is preceded by the keyword virtual.

Late binding is ensured in the PC class by declaring the function of the base class as virtual.

The following code segment contains the modified declaration of the get_ram_space() function
making the function virtual.
Class PC
{


virtual int get_ram_space();


};
class PC_XT : public PC
{


int get_ram_space();


};

class PC_AT : public PC_XT


{


int get_ram_space();


};

The get_ram_space() member function of the PC class is a virtual function. When a virtual function is
inherited, its virtual nature is also inherited. In the above code segment, the function
get_ram_space() in PC_XT and PC_AT classes is virtual.

Pure Virtual Functions

A pure virtual function is a virtual function without any executable statements. Often the virtual
functions of the base class are not used. For example, assume that the PC class you have seen earlier,
is derived from a microcomputer class. If the microcomputer class also has a get_ram_space()
function, it will never be invoked. This is because the microcomputer class is too generalized to have a
definite RAM size. Only the functions in the derived class will be invoked. In such situations, the body
of the virtual function can be removed.

A pure virtual function can be declared by equating the function declaration to zero. For example, the
statement
Virtual int get_ram_space() = 0;
declares the function get_ram_space() to be a pure virtual function.

Abstract Class

An abstract class is a class that contains at least one pure virtual function. An abstract class is used as
base class for deriving specific classes of the same kind. It defines properties common to other classes
derived from it. Since an abstract class contains one or more functions for which there is no
definition, no objects can be created using an abstract class. However, you can create pointers to an
abstract class. This allows an abstract class to be used as a base class. A pointer to an abstract class
can be used to select the proper virtual function.

File Pointers

The C++ input and output system manages two integer values associates with a file.
These are:

• get pointer – specifies the location in a file where the next read operation will occur.
• put pointer – specifies the location in a file where the next write operation will occur.
In other words, these pointers indicate the current positions for read and write operations,
respectively. Each time an input or an output operation takes place, the pointers are automatically
advances sequentially.

The term pointers should not be confused with normal C++ pointers used as address variables.

Often you may want to start reading an existing file from the beginning and continue sequentially
until the end. When writing, you ma want to start from the beginning, deleting any existing contents,
or appending new records (in which case you can open the file with the ios:app mode specifier).
These are default actions, so no manipulation of the pointers is necessary.

Sometimes you may have to manipulate file pointers to read from and write to a particular location in
a file. The seekg() and tellg() functions allow you to set and examine the get pointer, and the seekp()
and tellp() functions perform these same actions on the put pointer. In other words, these four
functions allow you to access the file in a non-sequential or random mode.

All the iostream clas objects can be repositioned by using either the seekg() or the seekp() member
function. These functions move the get and put pointers respectively to an absolute address within
the file or toa certain number of bytes from a particular position.

The tellg() and tellp() functions can be used to find out the current position of the get and put file
pointers respectively in a file.

The seekg() member function takes two arguments:


• Number of bytes to move.
• Reference in the file from which the pointer has to be repositioned.
For example:
If stream iFi1;
iFi1.seekg(10,ios:beg);
means, “position the get pointer 10 bytes from the beginning of the file”

The first argument is an integer that specifies the number of bytes positions(also called offset). The
second argument is the reference point. There are three reference points defined in the ios class:
• ios:beg – the beginning of the file.
• ios:cur – the current position of the file pointer
• ios:end – the end of the file

A negative value can also be specified for the first argument. For example, the following statement
moves the file pointer 20 bytes backward from the end of the file.
iFi1.seekg(-20,ios:end);

If the seekg() function is used with only one argument, the ios:beg reference point is assumed. For
example in the statement:
iFi1.seekg(16);

ios:beg will be the reference point and hence the get pointer will be positioned 16 bytes from the
beginning of the file.

The tellg() member function does not have any arguments. It returns the current byte position of the
get pointer relative to the beginning of the file. For example the statement:
intiPosition = iFi1.tellg();
will result in the variable iPosition having the value of the current position of the get pointer.

The seekp() and tellp() member functions are identical to the above two functions, but they are
identified with the put pointer. The seekg() and tellg() member functions are defined in the istream
class. The seekp() and tellp() member functions are defined in the istream class. The seekp() and
tellp() member functions are defined in the ostream class.

Program 20.1 finds out the number of records in the file billfile.dat by using the seekg() and tellg()
functions.

#include<fstream.h>
#include<iostream.h>
class bill
{
private:
intiBill_no;
floatfBill_amt;
public:
void getdata()
{
cout<<”Enter Bill number”;
cin>>iBill_no;
cout<<”Enter Bill amount”;
cin>>fBill_amt;
}
void showdata()
{
cout<<”Bill number ”<<iBill_no<<endl;
cout<<”Bill amount ”<<fBill_amt<<endl;
}
};
void main()
{
fstream Fi1(“billfile.dat”,ios::in);
Fi1.seekg(0,ios::end);
ini iEnd;
iEnd=Fi1.tellg();
cout<<”The size of the file is “<<iEnd<<endl;
cout<<”Size of one record is ”<<sizeof(bill)<<endl’
ini iNorec=iEnd/sizeof(bill);
cout<<”There are “<<iNored<<”records in the file”<<endl;
}

In the given program, the statement:


Fi1.seekg(0,ios::end);
is used to reach the end-of-file. The byte position is found by the following statement:
iEnd=Fi1.tellg();

The value of iEnd is divided by the size of one record to find out the number of records in the file.
 Querying a File

The seekg() and tellg() functions can also be used for querying. A query can be based on the record
number. For example, if the user wishes to see the 10th record,
ifstream ifile(“bill.dat”);
ifile.seekg(9 * sizeof(bill),ios:beg);

would position the record pointer at the beginning of the 10th record.

Program 20.2 is used to display any record from the file depending on the record number.

void query(void)
{
int num;
bill billobj;
ifstream ifile(“billfile.dat”);
ifile.seekg(0,ios::end);
int endpos = ifile.tellg();
int n = endpos/sizeof(bill);
cout<<”\n RECORD QUERY”;
cout<<”Which record do you want to query?”;
cout<<”Enter the record number”;
cin>>num;
int seekpos = (num-1) * sizeof(bill);
ifile.seekg(seekpos);
ifile.read((char *)&billobi.sizeof(bill));
cout<<\n The record is”;
billobj.showdata();
}

Similarly, a query can be based on the bill number. Program 20.3 is used to display a record based on
the bill number entered by the user.

#include<fstream.h>
#include<iostream.h>
class bill
{
private:
int iBill_no;
float fBill_amt;
public:
void getdata()
{
..
}
void showdata()
{
..
}
void query(void)
{
int num;
bill billobj;
ifstream ifile(“billfile.dat”);
ifile.seekg(0,ios::end);
int endpos = ifile.tellg();
int n = endpos/sizeof(bill);
cout<<”RECORD QUERY \n”<<endl;
cout<<”Enter the record number you want to query”;
cin>>num;
int seekpos = (num-1) * sizeof(bill);
ifile.seekg(seekpos);
ifile.read((char *)&billobj, sizeof(bill));
cout<<”The record is :\n”;
billobj.showdata();
}
};
void main()
{
bill bobj;
bobj.query();
}

Introduction to operator Overloading

We already know that a function can be overloaded (same function name having multiple
bodies). The concept of overloading a function can be applied to operators as well. This
session deals with overloading of operators to make Abstract Data Types(ADTS) more
natural, and closer to fundamental data types.

Need for Operator Overloading

Most fundamental data types have pre-defined operators associated with them. For example,
the C++ data type int, together with the operators +, -, *, and /, provides an implementation of
the mathematical concepts of an integer. To make a user-defined data type as natural as a
fundamental data type, the user-defined data type must be associated with the appropriate set
of operators.

Recall the fps_distance class, a user-defined class, which implements the British way of
measuring distance. The declaration of the class is given below:

class fps_distance
{
private:
int iFeet;
float fInch;
public:
fps_distance(int iFt,float fIn)
{
iFeet = iFt;
fInch = fln;
}
void disp_dist(void)
{
cout<<”Distance =”<<iFeet<<” ’ ”<<fInch<<” ‘ “<<endl;
}
};

If you want to add two distances stored in two objects of the fps_distance class, a function
needs to be invoked. For example,

object3.add_dist(object1, object2);

In this case, object1 is added to object2 and the result is stored in object3.

Similarly, to compare two distances, the following function call can be used:
object1.comp_dist(object2);

Here, the member function comp_dist of object1 is invoked with object2 as a parameter. This
function compares the data members of object1 with those of object2 and returns the
difference between them.
Using operators you can add two objects of the fps_distance class as follows:
object3 = object1 + object2;
where object1, object2 and object3 are all objects of the fps_distance class.

The above statement is clearer and easier to comprehend then the function call. Similarly, two
objects of fct_distance can be compared as follows:
object1>object2
or
object1<object2;
or
object1==object2;

The user can understand the operator notation more easily as compared to a function call
because it is closer to the real-life implementation. Thus, by associating a set of meaningful
operators, manipulation of an ADT can be done in a conventional and simpler form.
Associating operators with an ADT involves overloading them.

Recall the example discussed earlier where we added two objects of the fps_distance class and
stored the result in a third object using an operator.
object3 = object1+object2;

Note that the same ‘+’ operator that is used to add integers behaves differently when applied to
the ADT fps_distance.
Operator overloading refers to giving additional meaning to the normal C++ operators when
they are applied to ADTs. Only the pre-defined set of C++ operators can be overloaded. An
operator can be overloaded by defining a function for it. The function for the operator is
declared by using the operator keyword.

+ - * / % ^ & | ~ !
= < > += -= *= /= %= ^= &=
|= << >> <<= >>= == != <= >= &&
|| ++ -- , ->* -> () [] new delete
delete[
new[]                
]
 
Table 22.1 List of Operators that can be Overloaded

Table 22.1 List of Operators that can be overloaded


Unary operators are those which act on a single operand. Example of unary operators include
the increment (++) and decrement (--) operators. Program 22.1 overloads the ++ operators for
the fps_distance class to increment the data member iFeet by 1.

Class fps_distance
{
..
void operator++(void)
{
iFeet++;
}
..
};
void main()
{
fps_distance Fps(10,10.2);
++Fps;
Fps.disp_dist(); //displays 11
}

In Program 22.1, an object of the fps_distance class is created. The data member iFeet of the
FPS object is incremented by using the overloaded ++ operator. Unary operators are those
which act on a single operand. Examples of unary operators include the increment(++) and
decrement(--) operators.

Prefix and Postfix

Note that in Program 22.1 ‘++’ operator has been used as a prefix operator. Le us now discuss
this aspect of operator overloading.

The prefix application of an operator causes a variable to be incremented first before it is used
in an expression while the postfix application causes the value to be incremented after the
value is used in an expression.

However, the ‘++’ operator overloaded in Program 22.1 cannot be used as a postfix operator.
An operator function without any arguments is invoked by the compiler for the prefix
application of the operator. The compiler invokes the operator function with an int argument
for the postfix application of the operator.

For example,
int operator ++(int);
The int argument here is a dummy argument that is sued only to distinguish between the prefix
and the postfix application. The expression:
++x;
translates to
x.operator++();
and the expression:
x++;
translates to
x.operator++(0);

The value zero is automatically sent by the compiler.

Binary operators are operators that work with two operands. Examples of the binary operators
include arithmetic operators (+, -, *, /, %), arithmetic assignment operators (+=, -=, *=, /=) and
comparision operators(<.>,<= >=, ++, !=).

Overloading a binary operator is similar to overloading a unary operator except that a binary
operator requires an additional parameter.

Program 22.2 overloads the + binary operator to add two objects of the fps_distance class.

#include<iostream.h>
class fps_distanc
{
private:
int iFeet;
float fInch;
public:
fps_distance(int,float); //contructor
fps_distance();
fps_distance operator +(fps_distance&); //to overload the + operator
void disp_distance(void); //display in feet and inches
};
fps_distance :: fps_distance(int iFt, float fln)
{
iFeet = iFt;
fInch=fln;
}
fps_distance :: fps_distance()
{
iFeet =0;
fInch=0.0;
}
/* The ‘+’ operator needs two operands, one passed as a parameter and the other as the implicit object
*/
fps_distance fps_distance :: operator + (fps_distance &Fps2)
{
int iF = iFeet + Fps2.iFeet;
float fl = fInch + Fps2.fInch;
if (fl >= 12.0) //if the sum of inches is more than or equal to 12,
//iFeet has to be incremented by one
{
fl-=12.0;
iF++;
}
return fps_distance(iF,fl);
}
//Function to display in feet and inches
void fps_distance :: disp_distance()
{
cout<<”Distance=”<<iFeet<<”,”<<fInch<<”,”<<endl;
}
void main()
{
fps_distance Fps1(11,11.5);
fps_distance Fps2(10,10.7);
fps_distance Fps3;
Fps3 = Fps1 + Fps2;
Fps3.disp_distance();
}

In Program 22.2, the ‘+’ operator is overloaded to add two objects of the fps_distance class.
To add two fps_distance class objects, the feet and inches are added separately and a nameless
object is returned. The operator function receives one object as parameter. In the program,
Fps1 is the object of which the operator is a function and Fps2 is the object passed as
parameter to the operator. Hence, it needs only one argument. Whenever an overloaded
operator is invoked, the object on the left side of the operator is the object of which the
operator is a member, and the variable or constant on the right side is the parameter to the
operator.

Similarly, comparison operator can also be overloaded as follows:


..
int operator > (fps_distance &Fps2)
{
float fTemp1 = iFeet * 12 +fInch;
float fTemp2 = Fps2.iFeet * 12 + Fps2.fInch;
return ((fTemp1 > fTemp2) ? 1 : 0);
}
..

The ‘>’ overloaded operator compares an objects of the fps_distance class with iFeet.
 
 

You might also like