Lecture Notes On: Department of Computer Science & Engineering Jaipur Engineering College & Research Centre, Jaipur
Lecture Notes On: Department of Computer Science & Engineering Jaipur Engineering College & Research Centre, Jaipur
on
3CS4-06
Unit IV
/ P P P P P P P P P
Subject
O O O
Code
T CO O O O O O O O O O
1 1 1
/ 1 2 3 4 5 6 7 8 9
0 1 2
P
Understand the paradigms of
object oriented programming in 3 3 3 2 2 2 1 1 0 1 1 3
L
comparison of procedural
Object Oriented Programming
oriented programming.
Apply the class structure as
L programming.
fundamental, building block for
computational programming. 3 3 3 3 2 2 1 1 1 2 1 3
capacity in communication
3CS4-06
programming.
system.
Apply the major object-oriented
III concepts to implement object
L 3 3 3 3 2 1 2 2 1 2 1 3
oriented programs in C++.
Note that the type and scope of each static member variable must be defined outside the class
definition .This is necessary because the static data members are stored separately rather than as a
part of anobject.
Example:-
#include<iostream.h>
class item
{
static int count; //count is static
int number;
public:
void getdata(int a)
. {
number=a;
count++;
}
void getcount(void)
{
cout<<”count:”;
cout<<count<<endl;
}
};
int item :: count ; //count defined
int main( )
{
item a,b,c;
a.get_count( );
b.get_count( );
c.get_count( ):
a.getdata():
b.getdata();
The static Variable count is initialized to Zero when the objects created . The count is
incremented whenever the data is read into an object. Since the data is read into objects three times
the variable count is incremented three times. Because there is only one copy of count shared by all
the three object, all the three output statements cause the value 3 to be displayed.
output:- count : 2
count: 3
object number1
object number2
object number3
Like any other data type, an object may be used as A function argument. This can cone in two ways
1. A copy of the entire object is passed to thefunction.
2. Only the address of the object is transferred to thefunction
The first method is called pass-by-value. Since a copy of the object is passed to the function, any
change made to the object inside the function do not effect the object used to call the function.
The second method is called pass-by-reference . When an address of the object is passed, the called
function works directly on the actual object used in the call. This means that any changes made to the
object inside the functions will reflect in the actual object .The pass by reference method is more
efficient since it requires to pass only the address of the object and not the entire object.
Example:-
#include<iostream.h>
class time
{
int hours;
intminutes;
public:
void gettime(int h, int m)
{
hours=h;
minutes=m;
}
void puttime(void)
{
cout<< hours<<”hours and:”;
cout<<minutes<<”minutes:”<<end;
}
int main()
{
time T1,T2,T3;
T1.gettime(2,45);
T2.gettime(3,30);
T3.sum(T1,T2);
cout<<”T1=”;
T1.puttime( );
cout<<”T2=”;
T2.puttime( );
cout<<”T3=”;
T3.puttime( );
return(0);
}
OPERATOR OVERLOADING:-
Operator overloading provides a flexible option for the creation of new definations for most
of the C++ operators. We can overload all the C++ operators except the following:
Class members access operator (. ,.*)
Scope resolution operator (::)
Size operator(sizeof)
Condition operator (?:)
Although the semantics of an operator can be extended, we can't change its syntax, the
grammatical rules that govern its use such as the no of operands precedence and associativety. For
example the multiplication operator will enjoy higher precedence than the addition operator.
When an operator is overloaded, its original meaning is not lost. For example,
the operator +, which has been overloaded to add two vectors, can still be used to add two integers.
class complex
{
float real,img;
public:
complex()
{
real=0;
img=0;
}
complex(float r,float i)
{
real=r;
img=i;
}
void show()
{
cout<<real<<”+i”<<img;
}
complex operator+(complex &p)
{
complex w;
w.real=real+q.real;
w.img=img+q.img;
return w;
}
};
void main()
{
complex s(3,4);
complex t(4,5);
complex m;
m=s+t;
s.show();
t.show();
m.show();
}
Unary operator+ for adding two complex numbers (using friend function)
class complex
{
float real,img;
public:
complex()
{
real=0;
img=0;
}
complex(float r,float i)
{
real=r;
img=i;
}
void show()
{
cout<<real<<”+i”<<img;
}
friend complex operator+(complex &p,complex &q);
};
complex operator+(complex &p,complex &q)
{
complex w;
w.real=p.real+q.real;
w.img=p.img+q.img;
return w;
}
};
voidmain()
{
complex s(3,4);complex t(4,5);
complexm;
m=operator+(s,t);
s.show();t.show();
m.show();
}
Overloading an operator does not change its basic meaning. For example assume the +
operator can be overloaded to subtract two objects. But the code becomes unreachable.
class integer
{
intx, y;
public:
intoperator + ( ) ;
}
int integer: : operator + ( )
{
return (x-y) ;
}
Unary operators, overloaded by means of a member function, take no explicit argument and
return no explicit values. But, those overloaded by means of a friend function take one
reference argument (the object of the relevant class).
Binary operators overloaded through a member function take one explicit argument and those
which are overloaded through a friend function take two explicit arguments.
Table 7.2
Operator to Arguments passed to the Arguments passed to the Friend
Overload Member Function Function
Unary Operator No 1
Binary Operator 1 2
Type Conversions
In a mixed expression constants and variables are of different data types. The assignment operations
causes automatic type conversion between the operand as per certain rules.
The type of data to the right of an assignment operator is automatically converted to the data type of
variable on the left.
This converts float variable y to an integer before its value assigned to x. The type conversion is
automatic as far as data types involved are built in types. We can also use the assignment operator in
case of objects to copy values of all data members of right hand object to the object on left hand. The
objects in this case are of same data type. But of objects are of different data types we must apply
conversion rules for assignment.
There are three types of situations that arise where data conversion are between incompatible types.
1. Conversion from built in type to classtype.
2. Conversion from class type to built intype.
3. Conversion from one class type toanother.
This constructor builds a string type object from a char* type variable a. The variables length and
name are data members of the class string. Once you define the
constructor in the class string, it can be used for conversion from char* type to string type.
Example
string si , s2;
char* namel = “Good Morning”;
char* name2 = “ STUDENTS” ;
s1 = string(namel);
s2 = name2;
The program statement
si = string (namel);
first converts name 1 from char* type to string type and then assigns the string type values to the
object s1. The statement
s2 = name2;
Note that the constructors used for the type conversion take a single argument whose type is to be
converted.
In both the examples, the left-hand operand of = operator is always a class object. Hence, we can
also accomplish this conversion using an overloaded =operator.
Class to Basic Type
The constructor functions do not support conversion from a class to basic type. C++ allows us to
define a overloaded casting operator that convert a class type data to basic type. The general form of
an overloaded casting operator function, also referred to as a conversion function, is:
operator typename ( )
{
//Program statmerit .
}
This function converts a class type data to typename. For example, the operator double( ) converts a
class object to type double, in the following conversion function:
vector:: operator double ( )
{
double sum = 0 ;
for(int I = 0; ioize;
sum = sum + v[i] * v[i ]; //scalar magnitude
returnsqrt(sum);
}
In the string example discussed earlier, we can convert the object string to char* as follows:
string:: operator char*( )
{
return (str) ;
}
Example
Obj1 = Obj2 ; //Obj1 and Obj2 are objects of different classes.
Objl is an object of class one and Obj2 is an object of class two. The class two type data is converted
to class one type data and the converted value is assigned to the Objl. Since the conversion takes
place from class two to class one, two is known as the source and one is known as the destination
class.
Such conversion between objects of different classes can be carried out by either a
constructor or a conversion function. Which form to use, depends upon where we want the type-
conversion function to be located, whether in the source class or in the destinationclass.
We studied that the casting operator function
Operator typename( )
Converts the class object of which it is a member to typename. The type name may be a built-in type
or a user defined one(another class type) . In the case of conversions between objects,
typename refers to the destination class. Therefore, when a class needs to be converted, a
casting operator function can be used. The conversion takes place in the source class and the result is
given to the destination class object.
Let us consider a single-argument constructor function which serves as an instruction for
converting the argument's type to the class type of which it is a member. The argument belongs to
the source class and is passed to the destination class for conversion. Therefore the conversion
constructor must be placed in the destinationclass.
Table 7.3
When a conversion using a constructor is performed in the destination class, we must be able to
access the data members of the object sent (by the source class) as an argument. Since data members
of the source class are private, we must use special access functions in the source class to facilitate
its data flow to the destinationclass.
Consider the following example of an inventory of products in a store. One way of keeping record of
the details of the products is to record their code number, total items in the stock and the cost of each
item. Alternatively we could just specify the item code and the value of the item in the stock. The
following program uses classes and shows how to convert data of one type to another.
#include<iostream.h>
#include<conio.h>
class stock2;
class stock1
{
int code, item;
float price;
public:
stockl (int a, int b, float c)
{
code=a;
item=b;
price=c;
}
void disp( )
{
cout<<”code”<<code <<”\n”;
cout<<”Items”<<item <<”\n”;
cout<<”Price per item Rs . “<<price <<”\n”;
}
int getcode()
{return code; }
int getitem()
{return item; }
int getprice( )
{return price;}
operator float( )
{
return ( item*price );
}
};
class stock2
{
int code;
float val;
public:
stock2()
{
code=0; val=0;
}
stock2(int x, float y)
{
code=x; val=y;
}
void disp( )
{
cout<< “code”<<code << “\n”;
cout<< “Total Value Rs . “ <<val<<”\n”
}
stock2 (stockl p)
{
code=p . getcode ( ) ;
val=p.getitem( ) * p. getprice ( ) ;
}
};
void main ( )
{ '
Stockl il(101, 10,125.0);
Stock2 12;
float tot_val;
tot_val=i1 ;
i2=il;
cout<<” Stock Details-stockl-type” <<”\n”;
i 1 . disp ( ) ;
cout<<” Stock value”<<”\n”;
cout<< tot_val<<”\n”;
cout<<” Stock Details-stock2-type”<< “\n”;
i2 .disp( );
getch ( ) ;
}
Stock Details-stock2-type
code 10 1
Total Value Rs. 1250
Polymorphism:
Introduction
When an object is created from its class, the member variables and member functions are allocated
memory spaces. The memory spaces have unique addresses. Pointer is a mechanism to access these
memory locations using their address rather than the name assigned to them. You will study the
implications and applications of this mechanism in detail in this chapter.
Pointer is a variable which can hold the address of a memory location rather than the value at the
location. Consider the following statement
This statement instructs the compiler to reserve a 2-byte of memory location and puts the value 84 in
that location. Assume that the compiler allocates memory location 1001 to num. Diagrammatically,
the allocation can be shown as:
num Variablename
84 Value
Figure 9.1
As the memory addresses are themselves numbers, they can be assigned to some other variable For
example, ptr be the variable to hold the address of variable num.
Thus, we can access the value of num by the variable ptr. We can say “ptr points to num” as shown
in the figurebelow.
num num
84 1001
1001 2057
Fig 9.2
Pointers to Objects
An object of a class behaves identically as any other variable. Just as pointers can be defined in case
of base C++ variables so also pointers can be defined for an object type. To create a pointer variable
for the following class
class employee{
int code;
char name [20] ;
public:
inline void getdata ( )= 0 ;
inline void display ( )= 0 ;
};
The following codes is written
employee *abc;
This declaration creates a pointer variable abc that can point to any object of employee type.
this Pointer
C++ uses a unique keyword called "this" to represent an object that invokes a member function. 'this'
is a pointer that points to the object for which this function was called. This unique pointer is called
and it passes to the member function automatically. The pointer this acts as an implicit argument to
all the member function, fore.g.
class ABC
{
int a ;
-----
-----
};
The private variable „a‟ can be used directly inside a member function, like
a=123;
We can also use the following statement to do the same job.
this → a = 123
e.g.
class stud
{
int a;
public:
void set (int a)
{
this → a = a; //here this point is used to assign a class level
} „a‟ with the argument „a‟
void show ( )
{
cout << a;
}
};
main ( )
{
stud S1, S2;
S1.bet (5) ;
S2.show ();
}
o/p = 5
class base
{
//Data Members
//Member Functions
};
class derived : public base
{
//Data Members
//Member functions
};
void main ( ) {
base *ptr; //pointer to class base
derived obj ;
ptr =&obj; //indirect reference obj to thepointer
//Other Program statements
}
The pointer ptr points to an object of the derived class obj. But, a pointer to a derived class object
may not point to a base class object without explicit casting.
Forexample
class point {
intx;
inty ;
public:
virtual void display ( );
};
virtual void point: : display ( ) //error
{
Function Body
}
A virtual function cannot be a static member since a virtual member is always a member of a
particular object in a class rather than a member of the class as a whole.
class point {
int x ;
int y ;
public:
virtual static int length ( ); //error
};
int point: : length ( )
{
Function body
}
A virtual function cannot have a constructor member function but it can have the destructor member
function.
class point {
int x ;
int y ;
public:
virtual point (int xx, int yy) ; // constructors, error
void display ( ) ;
int length ( ) ;
};
A destructor member function does not take any argument and no return type can be specified for it
not even void.
class point {
int x ;
int y ;
public:
virtual point (int xx, int yy) ; //invalid
void display ( );
intlength ( ) ;
It is an error to redefine a virtual method with a change of return data type in the derived class with
the same parameter types as those of a virtuall method in the base class.
class base {
int x,y ;
public:
virtual int sum (int xx, int yy ) ; //error
};
class derived: public base {
intz ;
public:
virtual float sum (int xx, int yy) ;
};
The above declarations of two virtual functions are invalid. Even though these functions take
identical arguments note that the return data types aredifferent.
virtual int sum (int xx,intIT) ;//baseclass
virtual float sum (int xx, int IT) ; //derivedclass
Both the above functions can be written with int data types in the base class as well as in the derived
class as
virtual intsum (int xx,int yy) ;//base class virtual
intsum (int xx, int yy) ;//derived class
Only a member function of a class can be declared as virtual. A non member function (nonmethod)
of a class cannot be declaredvirtual.
virtual void display ( ) //error, nonmember function
{
Function body
}
Late Binding
As we studied in the earlier unit, late binding means selecting functions during the execution.
Though late binding requires some overhead it provides increased power and flexibility. The late
binding is implemented through virtual functions as a result we have to declare an object of a class
either as a pointer to a class or a reference to aclass.
For example the following shows how a late binding or run time binding can be carried out with the
help of a virtual function.
class base {
private :
int x;
float y;
public:
virtual void display ( ) ;
int sum ( ) ;
};
class derivedD : public baseA
{
private :
int x ;
float y;
public:
void display ( ); //virtual
int sum ( ) ;
};
void main ( )
{
baseA *ptr ;
derivedD objd ;
ptr = &objd ;
Other Program statements
ptr- >di splay ( ) ; //run time binding ptr-
>sum ( ) ; //compile time binding
}
Note that the keyword virtual is be followed by the return type of a member function if a run time is
to bebound. Otherwise, the compile time binding will be effected as usual. In the above program
segment, only the display ( ) function has been declared as virtual in the base class, whereas the sum
( ) is nonvirtual. Even though the message is given from the pointer of the base class to the objects of
the derived class, it willnot
access the sum ( ) function of the derived class as it has been declared as nonvirtual. The sum ( )
function compiles only the static binding.
The following program demonstrates the run time binding of the member functions of a class. The
same message is given to access the derived class member functions from the array of pointers. As
function are declared as virtual, the C++ compiler invokes the dynamic binding.
#include <iostream.h>
#include <conio.h>
class baseA {
public :
virtual void display () {
cout<< “One \n”;
}
};
class derivedB : public baseA
{
public:
virtual void display(){
cout<< “Two\n”; }
};
class derivedC: public derivedB
{
public:
virtual void display ( ) {
cout<< “Three \n”; }
};
void main ( ) {
//define three objects
baseA obja;
derivedB objb;
derivedC objc;
base A *ptr [3]; //define an array of pointers to baseA
ptr [0] =&obja;
ptr [1] = &objb;
ptr [2] =&objc;
for ( inti = 0; i <=2; i ++ )
ptr [i]->display ( ); //same message for all objects
getche ( );
}
Output
One
Two
Three
The program listed below illustrates the static binding of the member functions of a class. In program
there are two classes student and academic. The class academic is derived from class student. The
two member function getdata and display are defined for both the classes. *obj is defined for class
student, the address of which is stored in the object of the class academic. The functions getdata ( )
and display ( ) of student class are invoked by the pointer to theclass.
#include<iostream.h>
#include<conio.h>
class student {
private:
int rollno;
char name [20];
public:
void getdata ( );
void display ( );
};
class academic: public student {
private:
char stream;
public:
void getdata ( );
void display ( ) ;
};
void student:: getdata ( )
{
cout<< “enterrollno\n”;
cin>>rollno;
cout<< “enter name \n”;
cin>>name;
}
void student:: display ( )
{
cout<< “the student‟s roll number is “<<rollno<< “and name is”<<name ;
cout<< endl;
}
void academic :: getdata ( )
{
cout<< “enter stream of a student? \n”;
cin >>stream;
}
void academic :: display ( ) {
cout<< “students stream \n”;
cout <<stream<<endl;
}
void main ( )
{
student *ptr ;
academic obj ;
ptr=&obj;
ptr->getdata ( ) ;
ptr->display ( ) ;
getche ( );
}
output
enter rollno
25
enter name
raghu
the student‟s roll number is 25 and name is raghu
The program listed below illustrates the dynamic binding of member functions of a class. In this
program there are two classes student and academic. The class academic is derived from student.
Student function has two virtual functions getdata ( ) and display (). The pointer for student class is
defined and object . for academic class is created. The pointer is assigned the address of the object
and function of derived class are invoked by pointer to student.
#include <iostream.h>
#include <conio.h>
class student {
private:
introllno;
char name [20];
public:
virtual void getdata ( );
virtual void display ( );
};
class academic: public student {
private :
char stream[10];
public:
void getdata { };
void display ( ) ;
};
void student: : getdata ( )
{
cout<< “enter rollno\n”;
cin >> rollno;
cout<< “enter name \n”;
cin >>name;
}
void student:: display ( )
{
cout<< “the student‟s roll number is”<<rollno<< “and name is”<<name;
cout<< end1;
}
void academic: : getdata ( )
{
cout << “enter stream of a student? \n”;
cin>> stream;
}
void academic:: display ( )
{
cout<< “students stream \n”;
cout<< stream << endl;
}
void main ( )
{
student *ptr ;
academic obj ;
ptr = &obj ;
ptr->getdata ( );
ptr->dlsplay ( );
getch ( );
}
output
enter stream of a student?
Btech
students stream
Btech
Virtual destructors:
Just like declaring member functions as virtual, destructors can be declared as virtual, whereas
constructors can not be virtual. Virtual Destructors are controlled in the same way as virtual
functions. When a derived object pointed to by the base class pointer is deleted, destructor of the
derived class as well as destructor of all its base classes are invoked. If destructor is made as non
virtual destructor in the base class, only the base class‟s destructor is invoked when the object is
deleted.
#icnlude<iostream.h>
#include<string.h>
class father
{
protected:
char *fname;
public:
father(char *name)
{
fname=new char(strlen(name)+1);
strcpy(fname,name);
}
virtual ~father()
{
delete fname;
cout<<”~father is invoked…”;
}
#define size 5
class vector
{
int v[size];
public:
vector();
friend vector operator*(int a,vector b);
friend vector operator *(vector b,int a);
friend istream &operator>>(istream &,vector &);
friend ostream &operator<<(ostream &,vector &);
};
vector :: vector()
{
for(int i=0;i<size;i++)
v[i]=0;
}
vector::vector(int *x)
{
for (int i=0;i<size;i++)
v[i]=x[i];
}
vector operator*(int a,vector b)
{
vector c;
for(int i=0;i<size;i++)
c.v[i]=a*b.v[i];
return c;
}
32 P.T.O