2. Outline
Basics of polymorphism
Types of polymorphism
Compile and Run Time Polymorphism
Virtual Function
Object Slicing
Virtual Destructor
Dynamic Binding
2
3. Basics of Polymorphism
Greek word meaning - many or multiple forms.
In programming languages, polymorphism means that some code
or operations or objects behave differently in different contexts
It provides a single interface to entities of different types
Types of Polymorphism
3
Polymorphism
Operator Overloading
Function Overloading
Static Polymorphism Dynamic Polymorphism
Virtual Function
4. Basics of Polymorphism
Binding
Determining a location in memory by the compiler
Connecting a function call to a function body
The location may represent the following
Variable names bound to their storage memory address (offset)
Function names bound to their starting memory address (offset)
Two kinds of binding
Compile-time Binding (or) Static binding (or) Early binding
Run-Time Binding (or) Late binding
4
5. Static Polymorphism
Compile-time binding or early binding is called as static
polymorphism
Compile-Time Binding means
Compiler has enough information to determine an address
(offset)
Named variables / function calls have their addresses fixed
during compilation
5
6. Runtime Polymorphism
Dynamically choosing which function to call
It is just a way of choosing which function to execute when there are
multiple functions that match a function call
Remarkably, it permits us to delay choosing which function to call
until the moment of the call itself
6
9. Polymorphism Requirements
Inheritance
Upcasting
A pointer or reference variable (polymorphism cannot operate
through an automatic variable)
Function overriding
Virtual functions
9
10. Casting Objects
Casting is done with an operator:
(type)exp (C++ syntax) or
type(exp) (C Syntax)
The cast operator forms an expression
Casting does not change the original value
Example
double pi = 3.14159;
int i = (int)pi;
int i = int(pi);
The value stored in pi is unchanged
The value stored in i is 3
10
12. Casting Objects
Casting objects is only possible when the objects are instances of
classes related by inheritance
A Circle “is a” Shape
A Student “is a” Person
Makes no sense to cast an Student into a Shape
Upcasting
Upcasting takes place when a subclass object is converted into a
superclass object
Upcasts are safe and take place automatically without casting notation:
Circle* c = new Circle;
Shape* s = c;
12
16. Different ways of Upcasting
Taking the address of an existing object and assigning it to a part
pointer
D my_d;
B* a_ptr = &my_d;
Dynamically creating a new object and assigning the address to a
parent pointer
B* a_ptr = new D;
16
19. Downcasting vs Upcasting
Person* ceo = new Employee(...);
The statement instantiates an Employee object (the large rectangle) that has
five member variables - three that belong to Person (the blue part) and two
that belong to Employee (the green part). The Employee object is upcast to
a Person, which makes the id and phone members unreachable. Aside from
loosing access to the Employee members, the upcast causes no harm
Employee* cto = (Employee *)new Person(...);
Downcasting can create phantom members. The statement instantiates a
Person (parent) object but downcast it to an Employee (child) object. The
variable cto is a pointer to an Employee, which allows the compiler to access
the Person members, which is completely safe. However, being an
Employee pointer also allows the compiler to access the Employee
members, which were never created because it was a Person object that
was instantiated! Attempting to use the phantom members will produce
unpredictable and completely incorrect results
20
20. Object Slicing
Polymorphism requires a pointer or reference variable, and so
upcasting, also a requirement for polymorphism, is typically done
with pointers
What happens if we attempt an upcast with a value variable (i.e., a
variable that is neither a pointer nor a reference)?
21
21. Slicing
Upcasting without pointers results in slicing
Employee e(...);
Person p;
p = e;
An instance of Employee is created - it consists of a Person sub-
object and a part that is unique to Employee
An "empty" Person object is created; this operation allocates only
enough memory to hold a Person object
The Employee object is assigned (i.e., copied) to the Person object,
but the Person object does not have space (i.e., memory) to hold
the complete Employee object, and so the part of the Employee
object that lies beyond the Person subobject is sliced off
22
23. Function Overriding
Overloaded Functions
Are defined in the same class
Must have unique argument lists
May have different return types
Overridden Functions
Are defined in two classes that are related by inheritance
Must have the same name
Must have exactly the same argument list
Must have the same return type
24
31. Virtual Function Implementation
VTABLE (Virtual Table)
The compiler creates a VTABLE for every class and its derived
class having virtual functions, which contains addresses of virtual
functions
If no function is redefined in the derived class that is defined as
virtual in the base class, the compiler takes the address of base
class function.
VPTR ( Virtual Pointer)
When objects of base or derived classes are created, a void pointer
is inserted in the VTable called VPTR
32
32. Virtual Function Implementation
33
class Base
{
public :
Base() { }
virtual void f1() { cout<<”base::f1( )” << endl; }
virtual void f2( ) { cout << Base:: f2()”<<endl; }
void f3() { cout<<”Base :: f3()”<<endl; }
};
class Derived :public Base
{
public:
Derived() { }
void f1() { cout<<”Derived ::f1()”<<endl; }
};
void main()
{
Base b1;
Derived d1;
Base *p=&b1;
p->f1(); // base::f1
p->f2(); //base::f2
p->f3(); //base::f3
Base *q =&d1;
q->f1(); //Derived::f1
q->f2(); //Base::f2
q->f3(); //Base::f3
}
36. Pure Virtual Functions and Abstract
Classes
37
If we wanted to write the instructions for the Shape class draw function, what would
the code look like?
Or put another way, what does a shape look like? A shape, of course, is too general
or ambiguous - there are many kinds of shapes. In object-oriented terms, a Shape is
too abstract to draw, whereas a Circle, a Rectangle, or a Triangle are sufficiently
concrete to draw
37. Pure Virtual Functions and Abstract
Classes
Abstract Class
A class that serves only as a base class from which other classes can be
derived
If a base class contains pure virtual functions , no instance of the base
class can be created
Pure Virtual Functions
In practical applications, the member functions of base classes is rarely
used for doing any operation (null body).
Syntax: virtual void draw( )=0;
38
38. Pure Virtual Functions and Abstract
Classes
39
Employee has an abstract function and so is an
abstract class
The salaried and the sales employee classes override
the abstract function with concrete functions as so
become concrete classes
Abstract classes and functions are denoted in the
UML by writing their names in italic characters
39. Abstract Classes
Classes that have one or more pure virtual functions are said to be
abstract
Up to this point, all the classes that we have create or used have
been concrete
The difference between concrete and abstract classes is that you
may make an instance of a concrete class but you may not make an
instance of an abstract class
An abstract class can
be a base (parent or super) class
have concrete features (both variables and functions) that can be
inherited by derived (child or sub) classes
participate in (i.e., be the target of) an upcast
participate in polymorphism
40
40. Abstract Classes
41
class Base
{ public:
virtual void
show()=0;
// Pure Virtual
function
};
class Derv1 : public Base
{
public:
void show()
{ cout<<” In Derv 1”; }
};
class Derv2 : public Base
{ public:
void show()
{ cout<<”In Derv2”; }
};
main()
{
Base *List[2];
Derv1 dv1;
Derv2 dv2;
List[0]=&dv1;
List[1]=&dv2;
List[0]->show();
List[1]->show();
}
41. Virtual Destructors
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. For example, following program results in undefined
behavior
42
#include<iostream>
using namespace std;
class base {
public:
base()
{ cout<<"Constructing base n"; }
~base()
{ cout<<"Destructing base n"; }
};
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
Destructing base
42. Virtual Destructors
43
#include<iostream>
using namespace std;
class base {
public:
base()
{ cout<<"Constructing base n"; }
virtual ~base()
{ cout<<"Destructing base n"; }
};
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
Destructing derived
Destructing base