COMPBBE39312rObjrBh - OOP Unit 3 Polymorphism

You might also like

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 69

OOP

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

• Polymorphism is a key feature of object-oriented


programming that means having multiple forms.

3
TYPES OF POLYMORPHISM

Polymorphism

Compile
Run time
time

Function Operator Virtual


overloading overloading functions
4
COMPILE TIME(EARLY BINDING)

• The overloaded member functions are selected for invoking


based on their type and no. of arguments at compile time. This
is called early binding or static binding or static linking or
compile time polymorphism.

• Early binding means an object is bound to its function call at


compile time.

5
RUN TIME(LATE BINDING)

• To select which function should be invoked at run time, the


concept is known as run time polymorphism.

• In run time polymorphism the function call is linked with the


appropriate object much later after compilation, process is
termed as late binding.

• It is also called as dynamic binding

6
INTRODUCTION TO OVERLOADING

• Overloading occurs when the same operator or function name is


used with different signatures(in different form)

• for e.g. +/*/- used to do different behavior than usual.

• Both operators and functions can be overloaded in C++.

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;
}

float add(int c, int d)


{
return c+d;
}

long add(long e, long f)


{
return e+f; 11
}
OPERATOR OVERLOADING
• Normally
a = b + c;
works only with basic types such as int and float.
• If you are attempting to apply a = b + c;
when a, b, and c are objects of a user-defined class will cause
complaints from the compiler.

• However, using overloading, you can make this statement legal even
when a, b, and c are user-defined types.

• By using classes to create new kinds of variables, and operator


overloading to create new definitions for operators, one can extend
C++ to be, in many ways.

12
OPERATOR OVERLOADING(CNTD…)

• Overloaded operators should exhibit the functionality of their built-in


counterparts.
● E.g. the + operator should be overloaded to perform addition, not
subtraction.
● Avoid excessive or inconsistent use of operator overloading, as this
can make a program difficult to read.

13
RESTRICTIONS ON OPERATOR
OVERLOADING

• Cannot create new operators.

• 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

1. Class member access operator ( . )


2. Scope resolution operator( :: )
3. Pointer to member operator (.*)
4. Conditional operator(?:)
5. Size of operator(sizeof)

16
DEFINITION OF OPERATOR
OVERLOADING
• Operator function is used .

• Syntax :

Return type operator op(arg-list)


{

Function body // task goes here


}

Where operator is a keyword used to define operator function.

17
EXAMPLES
• Overloading of assignment operator.

• Overloading of unary operator.

• Overloading of binary operator.


(with and without using friend function)

• Overloading unary and binary operators using member and


friend functions.

18
RULES FOR OPERATOR OVERLOADING

• Only existing operators can be overloaded.


• New operators can not be created.
• We can not change the basic meaning of operator.
• Overloaded operator follows the syntax rules of the original operator.
• Unary operator – member function takes no argument
• Unary operator – friend function takes one argument
• Binary operator – member function takes one argument
• Binary operator – friend function takes two arguments

19
OPERATOR OVERLOADING(……)

• Operator functions can be either member functions or friend


functions.

• In member functions being operator function, function takes no


argument in case of unary operator and one argument in case of
binary operator .

• In friend functions being operator function, function takes one


argument in unary operator and two argument in Binary Operator
.

20
EXAMPLE

vector operator+(vector); → // binary addition

vector operator-(); // unary minus

friend vector operator+( vector, vector ); // binary addition

friend vector operator-( vector ); // unary minus

vector operator-( vector &a ); // binary subtraction

int operator= =(vector); // binary comparison


21
friend int operator= =(vector, vector); // binary comparison
OVERLOADING UNARY OPERATOR (USING MEMBER FUNCTION )
void data : :operator-()
class data {
{ x = -x;
int x, y; y = -y;
public : }
void get(int a, int b);
int main()
void display(); {
void operator-(); data d;
}; d.get(10, -20);
void data :: get(int a, int b) cout<< "d : ";
d.display();
{
-d; // activate operator funcn
x = a; cout<<" d : ";
y = b; d.display();
} return 0;
void data :: display() }
{
cout<<x<<" " ; O/P 22
cout<<y<<“ " ;
} d : 10 -20
d : -10 20
USING FRIEND (OVERLOADING UNARY OP)

friend void operator-(data &d); // declaration


void operator-(data &d) // definition
{
d.x = -d.x;
d.y = -d.y;
}

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
};

int main() Enter value of x for object no 1 : 10


{
cout<<"\nOperator Overloading "; add Enter value of x for object no 2 : 20
obj1,obj2,obj3;
obj1 + obj2 : 30 24
statement like
obj3= obj1.operator+(obj2)

can be changed to the much more readable form like


obj3=obj1+obj2

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)

2.Overloaded operator+ to add two complex numbers.

3.Overloaded operator* to multiply two complex numbers.

4.Overloaded << to print Complex Numbers.

5.Overloaded >> to read Complex Numbers

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;
}

friend ostream &operator<<( ostream &out, complex c );


27
friend istream &operator>>( istream &in, complex &c );

}
OVERLOADING BINARY OPERATOR
ostream &operator<<( ostream &out, complex c )
{
out <<c.real << "+" << c.img<<"i";
return out;
}

istream &operator>>( istream &in, complex &c )


{
in >> c.real >> c.img;
return in;
}

int main()
{
complex c1,c2,c3,c4;
cout<<"Enter real & imaginary part for complex no 1 : ";
cin>>c1;

cout<<"Enter real & imaginary part for complex no 2 : ";


cin>>c2;
28
cout<<"\nComplex no 1 is : "<<c1;
cout<<"\nComplex no 2 is : "<<c2;
OVERLOADING BINARY OPERATOR

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:

prajakta@prajakta-ThinkCentre-E73:~$ g++ ass2.cpp -o ass2


prajakta@prajakta-ThinkCentre-E73:~$ ./ass2

Enter real & imaginary part for complex no 1 : 1 2


Enter real & imaginary part for complex no 2 : 3 4

Complex no 1 is : 1+2i
Complex no 2 is : 3+4i

Addition of Complex no is : 4+6i


Multiplication of Complex no is : -5+10i 29
TYPE CONVERSION

• C++ allows us to convert data of one type to that of another.


This is known as type conversion.

• There are two types of type conversion in C++.


1.Implicit Conversion
2.Explicit Conversion (Type Casting)

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

• Conversion from one data type to another is prone to


data loss.

• This happens when data of a larger type is converted to


data of a smaller type.

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.

Both of these default activities (Assignment operator and Copy


constructor) are provided by the compiler.
If member-by member copying is what you want, you need take no further
action.
However, if you want assignment or initialization to do something more
complex, you can override the default functions.

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?

• In such situations, the compiler doesn’t handle things automatically and we


need to tell it what to do.

• These include
1) Conversions between basic types and user-defined types.
2) Conversions between different user-defined types.

39
DATA CONVERSIONS

1. Between User Defined type(objects) and Basic type

• 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.

• We must write these routines ourselves.

• This conversion can be


a) Basic type to User defined type(objects)
b) User defined type(objects) to Basic type.

40
DATA CONVERSIONS

A. Basic type to User defined type(objects)

• Conversion function to be defined in User defined objects class in the form


of constructor.

• This constructor function takes a single argument of basic type.

• Syntax:
Constructor(basic type)
{
//steps to convert basic type to object attributes.
}

41
DATA CONVERSIONS
B. User defined type(objects) to Basic type

• Conversion function to be defined in User defined objects class in the form


of operator function.

• This operator function is defined as an overloaded basic type which takes


no arguments.

• 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.

• NOTE: Here Conversion function has no return type specified, however42it


returns basic type value.
Conversion between User Defined type(objects) and Basic type
1) Basic type to User defined type(objects)
2) User defined type(objects) to Basic type.

#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

2. Between different user-defined types


• (conversion between objects of different classes)

• To convert between different user-defined data types, we can’t rely on built-in


conversion routines from compiler.

• Conversion methods can be used for this.

• This conversion methods can be


a) Constructor function
b) Operator function

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 .

• This conversion can be


a) In source objects class (use operator function)
b) In destination objects class (use constructor function)

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.

• You can make your listing more intuitive and readable.

• But it can also have the opposite effect, making your listing more ambiguous
and harder to understand.

• Guidelines for the same are:


1. Use Similar Meanings
2. Use Similar Syntax
3. Show Restraint
4. Avoid Ambiguity
5. Not All Operators Can Be Overloaded
49
KEYWORD explicit

• explicit

● Prefixing the explicit keyword with constructor prevents compiler


from using constructor for implicit conversion.

● Using explicit keyword makes conversion constructor to non-


conversion constructor and this make code less error prone.

● explicit keyword is used only with constructors.

50
KEYWORD mutable

• mutable

● Using mutable keyword the data members of a class with constant


object can be changed.

● const class objects:


• Object created using const keyword
• The data members of const object can not be changed.

51
RUN TIME POLYMORPHISM

• In runtime polymorphism, the function call is resolved at run time.

• In contrast, to compile time or static polymorphism, the compiler deduces the


object at run time and then decides which function call to bind to the object.

• Runtime polymorphism is also known as dynamic polymorphism or late


binding.

• Method overriding is an example of runtime 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.

● They are mainly used to achieve Runtime polymorphism

● Functions are declared with a virtual keyword in base class.

● The resolving of function call is done at Run-time 53


VIRTUAL FUNCTIONS
• Virtual functions provide a way for a program to decide while it is running what
function to 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;

// virtual function, binded at runtime


bptr->print();

// Non-virtual function, binded at compile time


bptr->show();
}

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)

Early binding(Compile time) is done according to the type of 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

1 Basic Compile time polymorphism means R un time polymorphism where at


binding is occurring at compile time run time we came to know which
method is going to invoke

2 Static/Dynamic
Binding It can be achieved through static It can be achieved through dynamic
binding binding

4. Inheritance Inheritance is not involved Inheritance is involved

5 Example Method overloading is  an example Method overriding is an example of


of compile time polymorphism runtime polymorphism

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.

• For example, let Shape be a base class.


• We cannot provide implementation of function draw() in Shape, but we know
every derived class(such as circle, rectangle, line etc.) must have implementation
of draw().

• We cannot create objects of abstract classes.

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.

We can have pointers and references of abstract class type.

If we do not override the pure virtual function in derived class, then derived
class also becomes abstract class.

An abstract class can have constructors.

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

You might also like