Polymorphism
Introduction
• ‘one name multiple forms’
• Implemented using overloaded functions and
operators
• Early binding or static binding or static linking.
Also known as compile time polymorphism,
simply means that an object is bound to its
function call at compile time
Polymorphism
Compile time
Run time Polymorphism
Polymorphism
Function Operator
Virtual Functions
Overloading Overloading
Why Do We Need Polymorphism?
Reason Benefit
Code Reusability Write once, use with different types or behaviors
Flexibility & Maintainability Easily extend systems using inheritance
Dynamic Behavior at Runtime Decide which function to call while program runs
Interface Abstraction Hide complexity; show a common interface
Types of Polymorphism in C++
Type Description Binding Time
1. Compile-Time Function/operator overloading Early binding
2. Run-Time Virtual function overriding Late binding
• How do we use member function show() class A
to print the values of objects of both {
classes A and B? int x;
public:
– Prototype of show() is same in both cases. So void show(){…}
static binding does not apply. };
– Can use class resolution operator(::) class B: public A
{
• Runtime polymorphism int y;
– Selecting appropriate member function while public:
the program is running void show(){…}
};
– Virtual function for this purpose
– a.k.a late binding or dynamic binding
Function Overloading (Compile-Time Polymorphism)
#include <iostream>
using namespace std;
void greet() {
cout << "Hello!\n";
}
void greet(string name) {
cout << "Hello, " << name << "!\n";
}
int main() {
greet(); // Output: Hello!
greet("Pratik"); // Output: Hello, Pratik!
}
Operator Overloading (Compile-Time Polymorphism)
#include <iostream>
using namespace std;
class Complex {
int real, imag;
public:
Complex(int r, int i) : real(r), imag(i) {}
Complex operator+(const Complex& obj) {
return Complex(real + obj.real, imag + obj.imag);
}
void display() {
cout << real << " + " << imag << "i\n";
}
};
int main() {
Complex c1(2, 3), c2(1, 4);
Complex c3 = c1 + c2; // Operator + overloaded
c3.display(); // Output: 3 + 7i
}
Function Overriding with Virtual Functions
#include <iostream> class Cat : public Animal {
using namespace std; public:
class Animal { void speak() override {
public: cout << "Cat meows\n";
virtual void speak() { }
cout << "Animal makes };
sound\n"; int main() {
} Animal* a; // Base class
}; pointer
class Dog : public Animal { Dog d;
public: Cat c;
void speak() override { a = &d;
cout << "Dog barks\n"; a->speak(); // Output: Dog
} barks
}; a = &c;
a->speak(); // Output: Cat
meows
}
A base class declares a function as virtual, and the derived class overrides it.
Pointers to Objects
• Consider the statement:
item x; What does it mean ?
• We can define a pointer of type item as
item *itemptr;
• Object pointers are useful in creating objects
at runtime
• We can also use an object pointer to access
public members of an object
• To declare item variable x and pointer to x:
item x;
item *ptr
ptr= &x; //ptr initialized with address of x
• class item
Member function of item can be referred to as:
{
x.getdata(10, 20.5) int code;
x.show(); float prices;
OR public:
ptr->getdata()10,20.5); void getdata(int a, float b)
{
ptr->show(); OR (*ptr).show();
code=a;
• We can also create the objects using pointers price=b;
and new operator: }
item *ptr=new item; void show(int a, int b)
• This allocates enough memory for the data {
members in the object structure and assigns the cout<<“Code: “<<code<<“\n”;
address of the memory space to ptr. cout<<“Price: “<<price<<“\n\n”;
• ptr can be used to refer the members as:
}
ptr->show();
• We can create array of objects using pointers: };
item *ptr = new item[10];
this Pointer
• Every object has a special pointer “this “
which points to the object itself
• This pointer is accessible to all the members
of the class but not to any static members of
the class
• Can be used to find the address of the object
in which the function is a member
this Pointer
• We create many instances of a class in a
program
• How do functions get to know which object
has called them
• The member functions are passes the pointers
of the calling object.
qMyInt.Get()
&qMyInt
this Pointer
• The pointer is passed with the name “this”
• “this” points to qMyInt
• Actually additional pointer parameter of the class
type that the function belongs to
memfun(Myclass* const this, arg1,…)
which we write as
memfun(arg1,..)
Pointers to derived classes
• Pointers can be used not only to base objects but also to objects
of derived classes
• Pointers to objects of a base are type-compatible with pointers
to objects of a derived class
• Therefore, a single pointer variable can be made to point to
objects belonging to different classes
• But there is a problem in using pointer to access the public
members of the derived class
• Only those members that are inherited from base class can be
accessed
• Those members which originally belong to derived class cannot
be accessed.
Pointers to derived classes
• In case a member of derived class has the
same name as one of the members of base
class, then any reference to that member by
pointer will always access the base class
member.
Virtual Functions
• Polymorphism refers to the property by which objects belonging to
different classes are able to respond to the same message, but in
different forms
• An essential requirement of polymorphism is therefore the ability
to refer to objects without any regard to their classes.
• This necessitates the use of single pointer variable to refer to the
objects of different classes
• When we use same function name in both base and derived classes,
the function in base class is declared as virtual.
• When a function is made virtual, c++ determines which function to
use at run time based on the type of object pointed by the base
pointer rather than the type of the pointer
Virtual functions
• We must access virtual function through the use of pointer
declared as a pointer to the base class.
• Why can’t we use the object name with dot operator the same
way as any other member function to call the virtual function?
• Yes, we can but run time polymorphism is achieved only when a
virtual function is accessed through a pointer to the base class.
Rules for Virtual Functions
• The virtual function must be member of some class, cannot be static
member
• They are accessed by using object pointer
• A virtual function can be a friend of another class
• The prototypes of base class version of virtual function and all
derived class version must be identical
• We cannot have virtual constructors but can have virtual destructors
• While a base class pointer can point to any type of derived object,
the reverse is not true
• When a base pointer points to a derived class, incrementing or
decrementing it will not make it point to the next object of derived
class
Pure Virtual Function
• A virtual function is usually declared in base class and redefined in
the derived classes.
• The function in base class only serves as place holders, also are
“empty”.
• If we define such functions as:
– virtual void display()=0;
• Such functions are called pure virtual functions.
• The derived classes should either define the function or re-declare
it as pure virtual.
• The class containing pure virtual function cannot be used to declare
any object of its own.
• Such classes are called abstract base classes
Early Binding and Late Binding
• http://www.learncpp.com/cpp-tutorial/124-
early-binding-and-late-binding/