Professional Documents
Culture Documents
COMPBBE39312rObjrBh - OOP Unit 3 Polymorphism
COMPBBE39312rObjrBh - OOP Unit 3 Polymorphism
COMPBBE39312rObjrBh - OOP Unit 3 Polymorphism
UNIT 3: POLYMORPHISM
1
CONTENTS
• Polymorphism
• Types of Polymorphism
• Overloading
● Introduction to overloading
● Need of function overloading and operator overloading
• Operator Overloading- concept of overloading
• Operator overloading
• Overloading Unary Operators
• Overloading Binary Operators
• Type conversions [implicit and explicit (type casting)]
• Data conversions
• Pitfalls of Operator Overloading and Conversion
• Keywords explicit and mutable
• Run Time Polymorphism
● Pointers to Base class
● virtual function and its significance in C++
● pure virtual function and virtual table
● virtual destructor 2
● abstract base class
POLYMORPHISM
3
TYPES OF POLYMORPHISM
Polymorphism
Compile
Run time
time
5
RUN TIME(LATE BINDING)
6
INTRODUCTION TO OVERLOADING
7
NEED OF OVERLOADING
• The motivation behind function overloading is to be able to use
similar function calls to functions that essentially do the same
thing, but process different data types.
• To make sure that the operator performs two or more than two
operations at two different instances.
• To make user defined data types work as standard data types, use
operator overloading.
• int, float directly can be added what about adding two objects ??
8
FUNCTION OVERLOADING
• Function Overloading is the ability to have multiple functions
with the same name, but with different signatures.
• C++ supports writing more than one function with the same
name but different argument lists. This could include:
● different data types
● different number of arguments
● The advantage is that the same apparent function can be called to perform
similar but different tasks.
9
FUNCTION OVERLOADING
• Function having same name different signatures.
e.g.
int add(int a, int b);
float add(float c, float d);
long add(long e, long f);
int main()
{
int a=10, b=20,sum_int;
float c= 20.5, d=20.5,sum_float
long int e =1000, f =2000,sum_long;
sum_int = add(a,b);
sum_float = add(c,d);
sum_long = add(e,f); 10
}
FUNCTION DEFINITIONS
int add(int a, int b)
{
return a+b;
}
• However, using overloading, you can make this statement legal even
when a, b, and c are user-defined types.
12
OPERATOR OVERLOADING(CNTD…)
13
RESTRICTIONS ON OPERATOR
OVERLOADING
• Cannot change
● Precedence of operator (order of evaluation)
• Use parentheses to force order of operators
● Associativity (left-to-right or right-to-left)
● Number of operands
• e.g., & is unary, can only act on one operand
● How operators act on built-in data types (i.e., cannot change integer
addition)
● Meaning of the operator if its adding, it will still add but with different
arguments
14
OPERATORS CAN BE OVERLOADED
15
OPERATORS CAN NOT BE OVERLOADED
16
DEFINITION OF OPERATOR
OVERLOADING
• Operator function is used .
• Syntax :
17
EXAMPLES
• Overloading of assignment operator.
18
RULES FOR OPERATOR OVERLOADING
19
OPERATOR OVERLOADING(……)
20
EXAMPLE
23
OVERLOADING BINARY OPERATOR( MEMBER FUNCTION )
#include <iostream> cout<<"\nEnter value of x for object no 1 : ";
using namespace std;
class add cin>>obj1.x;
{ public: cout<<"\nEnter value of x for object no 2 : ";
int x;
add()
{ x = 0; } cin>>obj2.x;
add(int arg1) obj3=obj1+obj2;
{ x = arg1; } cout<<"\nobj1 + obj2 : "<<obj3.x; return 0;
add operator + (add o1) }
{
add temp;
temp.x=x+o1.x; Output :
return temp;
} Operator Overloading
};
25
OVERLOADING BINARY OPERATORS
Implement a class Complex which represents the Complex Number data type.
Implement the following operations:
1.Constructor
(including a default constructor which creates the complex number 0+0i)
26
OVERLOADING BINARY OPERATOR
#include <iostream> complex operator + (complex c)
using namespace std; {
class complex complex temp;
{ temp.real=real+c.real;
private: temp.img=img+c.img;
float real; return temp;
float img; }
public:
complex() complex operator * (complex c)
{ {
real = 0; complex temp;
img = 0; temp.real=real*c.real-img*c.img;
} temp.img=real*c.img+img*c.real;
complex(float r, float i) return temp;
{ }
real = r;
img = i;
}
}
OVERLOADING BINARY OPERATOR
ostream &operator<<( ostream &out, complex c )
{
out <<c.real << "+" << c.img<<"i";
return out;
}
int main()
{
complex c1,c2,c3,c4;
cout<<"Enter real & imaginary part for complex no 1 : ";
cin>>c1;
c3=c1+c2;
cout<<"\nAddition of Complex no is : "<<c3;
c4=c1*c2;
cout<<"\nMultiplication of Complex no is : "<<c4<<endl;
return 0;
}
O/P:
Complex no 1 is : 1+2i
Complex no 2 is : 3+4i
30
IMPLICIT TYPE CONVERSION
Type conversion that is done automatically done by the compiler is known as
implicit type conversion.
// Example
#include <iostream>
using namespace std;
int main()
{ int num_int = 9;
double num_double;
// implicit conversion, assigning int value to a double variable
num_double = num_int;
cout << "num_int = " << num_int << endl;
cout << "num_double = " << num_double << endl;
return 0;
}
O/P : num_int = 9 31
num_double = 9
IMPLICIT TYPE CONVERSION
// Example 2
#include <iostream>
using namespace std;
int main() {
int num_int;
double num_double = 9.99;
// implicit conversion, assigning a double value to an int variable
num_int = num_double;
cout << "num_int = " << num_int << endl;
cout << "num_double = " << num_double << endl;
return 0;
}
O/P :
num_int = 9
num_double = 9.99 32
DATA LOSS DURING CONVERSION
33
34
EXPLICIT TYPE CONVERSION
• When the user manually changes data from one type to another, this is known as
explicit conversion. This type of conversion is also known as type casting.
• This is done by explicitly defining the required type in front of the expression in
parenthesis.
• Example
#include <iostream>
int main()
{
double num_double = 3.56;
cout << "num_double = " << num_double << endl;
// C-style conversion from double to int
O/P :
int num_int1 = (int)num_double;
cout << "num_int1 = " << num_int1 << endl; num_double = 3.56
num_int1 = 3
// function-style conversion from double to int num_int2 = 3
int num_int2 = int(num_double);
35
cout << "num_int2 = " << num_int2 << endl;
}
ASSIGNMENT AND COPY INITIALIZATION (REVISION)
• C++ compiler is always busy on your behalf, doing things you can’t be
bothered to do.
• Two important examples of this process are
● Assignment operator
● Copy constructor.
• Assignment operator
• We’ve used the assignment operator several times, possibly without thinking
too much about it.
• Assume obj1 and obj2 are objects. Unless you tell the compiler otherwise,
the statement
● obj2 = obj1; // set obj2 to the value of obj1
• It will cause the compiler to copy the data from a1, member by member, into
a2.
• This is the default action of the assignment operator = 36
• Copy constructor.
• Initializing an object with another object, as in
● Class_xyz obj2(obj1); // initialize obj2 to the value of obj1
• The compiler creates a new object, obj2 and copies the data from obj1,
member by member, into obj2.
• This is the default action of the copy constructor.
37
DATA CONVERSIONS
1. We know that the = operator will assign a value from one variable to
another, in statements like
● intvar1 = intvar2;
● where intvar1 and intvar2 are integer variables.
2. Also the = operator assigns the value of one user-defined object to another,
provided they are of the same type, in statements like
● obj3= obj2 + obj1;
● where the result of the addition, which is of class type, is assigned to another object of
same class type obj3.
• Here, compiler doesn’t need any special instructions to use = operator for the
assignment of user-defined objects such as class objects.
• But what happens when the variables on different sides of the = are of
different types? 38
DATA CONVERSIONS
• Thus, assignments between types, whether they are basic types or user-
defined types, are handled by the compiler with no effort on our part,
provided that the same data type is used on both sides of the equal sign.
• But what happens when the variables on different sides of the = are of
different types?
• These include
1) Conversions between basic types and user-defined types.
2) Conversions between different user-defined types.
39
DATA CONVERSIONS
• To convert between user-defined data types and basic types, we can’t rely on
built-in conversion routines, as the compiler doesn’t know anything about
user-defined types.
40
DATA CONVERSIONS
• Syntax:
Constructor(basic type)
{
//steps to convert basic type to object attributes.
}
41
DATA CONVERSIONS
B. User defined type(objects) to Basic type
• Syntax:
operator Basic type()
{
//steps to convert object attributes to basic type.
}
• It converts members of an object to basic type and return basic data item.
#include <iostream>
using namespace std;
class Meter
{float length;
public:
Meter()
{
length = 0.0;
}
Meter (float il)
{
length=il/100.0;
}
operator float()
{
float temp;
temp=length*100.0;
43
return temp;
}
void get()
{
cout<<"\nEnter Length : : (in m)";
cin>>length;
}
void disp()
{
cout<<"\n\tLength : (in meters) "<<length;
}
};
int main()
{
Meter m1,m2;
float l1,l2;
cout<<"\nEnter Length : (in cm) ";
cin>>l1;
m1=l1; //Basic type to User defined type(objects)
m1.disp();
m2.get();
l2=m2; //or l2=(float)m2; // User defined type(objects) to Basic type.
cout<<"\n\tLength : (in cm) "<<l2; 44
}
DATA CONVERSIONS
45
DATA CONVERSIONS
• The choice between the two conversion methods depends on the placement
of conversion method.
• E.g.
classA objA;
classB objB;
objA=objB;
• Conversion method can be defined in classA or classB .
46
DATA CONVERSIONS
Conversion method in source objects class (operator function)
• E.g. objA=objB;
//Where objB is source object and objA is destination object.
• Syntax:
class classA
{ //class A stuff
};
class classB
{ //class B attributes
public:
operator classA()
{ //steps to convert classB object to classA attributes.
}
……..
…….. 47
};
DATA CONVERSIONS
Conversion method in destination objects class
(constructor function)
• E.g. objA=objB;
//Where objB is source object and objA is destination object.
• Syntax:
class classB
{ //class B stuff
};
class classA
{ //class A attributes
public:
classA(classB object)
{ //steps to convert classB object to classA attributes.
}
…….. 48
……..
};
PITFALLS OF OPERATOR OVERLOADING AND CONVERSION
• Operator overloading and type conversions give you the ability to redefine the
building blocks of the language.
• But it can also have the opposite effect, making your listing more ambiguous
and harder to understand.
• explicit
50
KEYWORD mutable
• mutable
51
RUN TIME POLYMORPHISM
52
VIRTUAL FUNCTIONS
• A virtual function is a member function which is declared within a base class and
is re-defined(Overridden) by a derived class.
• When you refer to a derived class object using a pointer or a reference to the base
class, you can call a virtual function for that object and execute the derived class’s
version of the function.
● Virtual functions ensure that the correct function is called for an object, regardless of the type
of reference (or pointer) used for function call.
• Virtual functions make possible greater flexibility in performing the same kind of
action on different kinds of objects.
• They allow the use of functions called from an array of type pointer-to-base that
actually holds pointers (or references) to a variety of derived types.
• Typically a function is declared virtual in the base class, and other functions with
the same name are declared in derived classes.
54
VIRTUAL FUNCTIONS EXAMPLE
class base
{ public:
virtual void print()
{ cout << "print base class" << endl;
}
void show()
{ cout << "show base class" << endl;
}
};
class derived : public base
{ public:
void print()
{ cout << "print derived class" << endl;
}
void show()
55
{ cout << "show derived class" << endl;
}
VIRTUAL FUNCTIONS EXAMPLE
int main()
{
base* bptr;
derived d;
bptr = &d;
Output:
print derived class
56
show base class
57
Nonvirtual pointer access.
58
Virtual pointer access.
WORKING OF VIRTUAL FUNCTIONS (CONCEPT OF VTABLE AND
VPTR)
If a class contains a virtual function, then compiler itself does two things:
If object of that class is created, then a virtual pointer(VPTR) is inserted as a data
member of the class to point to VTABLE of that class.
For each new object created, a new virtual pointer is inserted as a data member of that class.
Irrespective of object is created or not, a static array of function pointer called VTABLE
where each cell contains the address of each virtual function contained in that class.
NOTE:
For every class that defines or inherits virtual functions the compiler creates a virtual
table.
The virtual table stores a pointer to the most specific definition of each virtual function.
The compiler has to find the right function definition (i.e. the most specific one) at
runtime. This process is called dynamic dispatch or late method binding.
59
WORKING OF VIRTUAL FUNCTIONS (CONCEPT OF VTABLE AND
VPTR)
60
POINTS TO NOTE:
Runtime polymorphism is achieved only through a pointer (or reference) of base class type.
A base class pointer can point to the objects of base class as well as to the objects of derived
class.
Late binding(Runtime) is done in accordance with the content of pointer (i.e. location pointed
to by pointer)
In previous code, base class pointer ‘bptr’ contains the address of object ‘d’ of derived class.
Since print() function is declared with virtual keyword so it will be bound at run-time (output
is print derived class as pointer is pointing to object of derived class )
show() is non-virtual so it will be bound during compile time(output is show base class as
pointer is of base type ).
61
DIFFERENCE BETWEEN COMPILE-TIME
POLYMORPHISM AND RUNTIME
POLYMORPHISM
Sr.
No. Key Compile-time polymorphism Runtime polymorphism
2 Static/Dynamic
Binding It can be achieved through static It can be achieved through dynamic
binding binding
62
ABSTRACT CLASSES IN C++
• Sometimes implementation of all function cannot be provided in a base class
because we don’t know the implementation.
Such a class is called abstract class.
63
PURE VIRTUAL FUNCTION
• A pure virtual function (or abstract function) in C++ is a virtual function for which
we don’t have implementation, we only declare it.
• A pure virtual function is declared by assigning 0 in declaration.
• A pure virtual function is implemented by classes which are derived from an
Abstract class.
• Example:
// An abstract class
class Test
{ // Data members of class
public:
virtual void show() = 0; // Pure Virtual Function
/* Other members */
};
64
PURE VIRTUAL FUNCTIONS EXAMPLE
class Base
{
public:
virtual void show() = 0;
};
class Derived: public Base
{
public:
void show()
{ cout << "In Derived \n"; }
};
int main(void)
{
Base *bp = new Derived();
bp->show();
return 0;
} 65
Output:
In Derived
PURE VIRTUAL FUNCTION
• NOTE:
A class is abstract if it has at least one pure virtual function.
If we do not override the pure virtual function in derived class, then derived
class also becomes abstract class.
66
VIRTUAL DESTRUCTOR
• Since derived classes are often handled via base class references, declaring a non-
virtual destructor will be dispatched statically, mystifying the destructor of the
derived class.
• So deleting a derived class object using a pointer of base class type that has a non-
virtual destructor results in undefined behavior.
• To correct this situation, the base class should be defined with a virtual destructor.
• Example:
class base
{
public:
base()
{ cout<<"Constructing base \n"; }
virtual ~base()
{ cout<<"Destructing base \n"; }
}; 67
VIRTUAL DESTRUCTOR CONT.
class derived: public base
{ public:
derived()
{ cout<<"Constructing derived \n"; }
~derived()
{ cout<<"Destructing derived \n"; }
};
int main(void)
{ derived *d = new derived();
base *b = d;
delete b;
}
Output:
Constructing base
Constructing derived
68
Destructing derived
Destructing base
END
69