Module 7
Polymorphism
Polymorphism
• Polymorphism, (Greek term) - ability to take more than one
form.
• An operation may exhibits different behaviors in different
instances. The behavior depends upon the type of data used
in the operation.
• For example consider the operation of addition for two
numbers; the operation will generate a sum. If the operands
are string then the operation would produce a third string by
concatenation.
• The process of making an operator to exhibit different
behavior in different instances is known operator overloading
Function overloading
• Function overloading is a feature of object-oriented
programming where two or more functions can have
the same name but different parameters.
• In Function Overloading “Function” name should be
the same and the arguments should be different.
• Function overloading can be considered an example
of a polymorphism feature in C++.
•The parameters should follow any one or more than one of the
following conditions for Function overloading:
•Parameters may have a different type
add(int a, int b)
add(double a, double b)
•Parameters may have a different number
add(int a, int b)
add(int a, int b, int c)
•Parameters may have a different sequence of parameters.
add(int a, double b)
add(double a, int b)
#include <iostream>
using namespace std;
void add(int a, int b)
{
cout << "sum = " << (a + b);
}
void add(double a, double b)
{
cout << endl << "sum = " << (a + b);
}
int main()
{
add(10, 2);
add(5.3, 6.2);
return 0;
}
Output:
sum = 12
sum = 11.5
• Function overloading is possible only if the functions
differ from each other by the types and the number
of arguments in the argument list.
• However, functions can not be overloaded if they
differ in their return type.
– Example: if there are two functions: int sum() and float
sum(), these two will generate a compile-time error as
function overloading is not possible here.
#include <iostream>
int fun() { return 10; }
char fun() { return 'a’; } // compiler error as it is a new declaration of fun()
int main()
{
char x = fun();
getchar();
return 0;
}
Output
prog.cpp: In function ‘char fun()’:
prog.cpp:6:10: error: ambiguating new declaration of ‘char fun()’
char fun() { return 'a'; }
^
prog.cpp:4:5: note: old declaration ‘int fun()’
int fun() { return 10; }
^
Function Overriding
• Function overriding is the mechanism using which a function
defined in the base class is once again defined in the derived class.
In this case, we say the function is overridden in the derived class.
• We should remember that function overriding cannot be done
within a class.
• The function is overridden in the derived class only.
• Hence inheritance should be present for function overriding.
• The second thing is that the function from a base class that we are
overriding should have the same signature or prototype i.e. it
should have the same name, same return type and same
argument list.
#include <iostream>
using namespace std;
class Base
{
public:
virtual void show_val()
{
cout << "Class::Base"<<endl;
}
};
class Derived:public Base
{
public:
void show_val() //function overridden from base
{
cout << "Class::Derived"<<endl;
}
};
int main()
{
Output:
Base b;
Derived d; Class::Base
b.show_val(); Class::Derived
d.show_val();
}
Function Overloading vs Function Overriding
• Function Overloading provides multiple
definitions of the function by changing signature
i.e. changing number of parameters, change
datatype of parameters, return type doesn’t play
any role.
• It can be done in base as well as derived class
• Example:
void area(int a);
void area(int a, int b);
Function Overriding (achieved at run time)
• It is the redefinition of base class function in its derived class with same signature i.e.
return type and parameters.
• It can only be done in derived class.
Example:
Class a
{
public:
virtual void display(){ cout << "hello"; }
};
Class b:public a
{
public:
void display(){ cout << "bye";}
};
#include<iostream>
using namespace std;
class BaseClass
{
public:
virtual void Display()
{
cout << "\nThis is Display() method of BaseClass";
}
void Show()
{
cout << "\nThis is Show() method of BaseClass";
}
};
class DerivedClass : public BaseClass
{
public:
void Display() // Overriding method - new working of base class display method
{
cout << "\nThis is Display() method of DerivedClass";
}
};
int main()
{ Output:
DerivedClass dr; This is Display() method of DerivedClass
BaseClass &bs = dr;
This is Show() method of BaseClass
bs.Display();
dr.Show();
}
Function Overloading Function Overriding
Function Overloading provides multiple Function Overriding is the redefinition of base
definitions of the function by changing class function in its derived class with same
signature. signature.
An example of compile time polymorphism. An example of run time polymorphism.
Function signatures should be different. Function signatures should be the same.
Overloaded functions are in same scope. Overridden functions are in different scopes.
Overloading is used when the same function Overriding is needed when derived class
has to behave differently depending upon function has to do some different job than the
parameters passed to them. base class function.
A function has the ability to load multiple A function can be overridden only a single
times. time.
In function overloading, we don’t need In function overriding, we need an inheritance
inheritance. concept.
OPERATOR OVERLOADING
Operator Overloading in C++
• Operator overloading is a compile-time
polymorphism.
• It is an idea of giving special meaning to an existing
operator in C++ without changing its original meaning.
• In C++, we can make operators work for user-defined
classes.
• This means C++ has the ability to provide the
operators with a special meaning for a data type, this
ability is known as operator overloading.
• For example, we can overload an operator ‘+’ in a class like
String so that we can concatenate two strings by just using +.
• Another example is classes, where arithmetic operators may be
overloaded, which are Complex Numbers, Fractional Numbers,
Big integers, etc.
Example:
int a;
float b, sum;
sum = a + b;
class A { In this example, we have 3
statements; variables “a1”, “a2” and “a3” of
}; type “class A”. Here we are trying
to add two objects “a1” and “a2”,
int main()
which are of user-defined type i.e.
{
of type “class A” using the “+”
A a1, a2, a3;
operator. This is not allowed,
because the addition operator “+”
a3 = a1 + a2;
is predefined to operate only on
built-in data types. But here, “class
A” is a user-defined type, so the
return 0;
compiler generates an error. This is
}
where the concept of “Operator
overloading” comes in.
• Now, if the user wants to make the operator “+” add
two class objects, the user has to redefine the
meaning of the “+” operator such that it adds two
class objects.
• This is done by using the concept of “Operator
overloading”.
• Redefining the meaning of operators really does not
change their original meaning; instead, they have
been given additional meaning along with their
existing ones.
Operators that can be overloaded
We can overload:
• Unary operators
• Binary operators
• Special operators ( [ ], (), etc)
But, among them, there are some operators that cannot be overloaded. They
are
• Scope resolution operator ::
• Member selection operator ?:
• Member selection through .
Restrictions on Operator Overloading
C++ operators that can be overloaded
Operators that can be overloaded
+ - * / % ^ & |
~ ! = < > += -= *=
/= %= ^= &= |= << >> >>=
<<= == != <= >= && || ++
-- ->* , -> [] () new delete
new[] delete[]
C++ Operators that cannot be overloaded
Operators that cannot be overloaded
. .* :: ?: sizeof
General Format
returnType operator*(parameters);
any type keyword operator symbol
• Return type may be whatever the operator returns
• Including a reference to the object of the operand
• Operator symbol may be any overloadable operator from
the list.
2
1
Example
//inside the class //outside the class definition requires scope resolution operator
#include<iostream> #include<iostream>
Using namespace std; Using namespace std;
class Marks{
class Marks{
int intmark,extmark;
int intmark,extmark;
public:
public:
Marks() // default constructor for initializing the zero value
Marks() // default constructor for initializing the zero value {
{ intmark = 0;
intmark = 0; extmark = 0;
extmark = 0; }
} Marks ( int im, int em) // constructor for taking the values and storing the
Marks ( int im, int em) // constructor for taking the values and value into class members
storing the value into class members {
{ intmark =im;
intmark =im; extmark em;
extmark em; }
}
void display(){
cout << intmark<<endl<<extmark<<endl;
void display(){
}
cout << intmark<<endl<<extmark<<endl;
Marks operator+(Marks m)
} };
Marks operator+(Marks m) { Mark Marks :: operator+(Marks m) {
Marks temp; Marks temp;
temp.intmark = intmark + m.intmark; temp.intmark = intmark + m.intmark;
temp.extmark = extmark + m.extmark; temp.extmark = extmark + m.extmark;
return temp;} return temp;}
};
Int main(){
Int main(){ Marks m1(10,20), m2 (30,40);
Marks m3 = m1 + m2;
Marks m1(10,20), m2 (30,40);
m3.display();
Marks m3 = m1 + m2;
return 0;
m3.display();
return 0;
#include <iostream>
Example
using namespace std;
class Complex {
private:
int real, imag;
public:
Complex(int r = 0, int i = 0)
{
real = r;
imag = i;
}
// This is automatically called when '+' is used with between two Complex
objects
Complex operator+(Complex const &obj)
{
Complex res;
res.real = real + obj.real;
res.imag = imag + obj.imag;
return res;
}
void print() { cout << real << " + i" << imag << '\n'; }
};
int main()
{
Output
Complex c1(10, 5), c2(2, 4); 12 + i9
Complex c3 = c1 + c2;
c3.print();
}
Overloading Unary
#include <iostream>
Operator
using namespace std;
class temp
{
private:
int count;
public:
temp():count(5)
{}
void operator ++()
{
count=count+1;
}
void Display()
{
cout<<"Count: "<<count;
}
};
int main()
{
temp t;
++t; // operator function void operator ++() is being called
t.Display(); Output
Count: 6
13 return 0;
}
#include <iostream>
using namespace std;
class Distance {
private:
Example unary operator
int feet; // 0 to infinite
int inches; // 0 to 12
public:
// required constructors
Distance() {
feet = 0;
inches = 0;
}
Distance(int f, int i) {
feet = f;
inches = i;
}
// method to display distance
void displayDistance() {
cout << "F: " << feet << " I:" << inches <<endl;
}
// overloaded minus (-) operator
Distance operator- () {
feet = -feet;
inches = -inches;
return Distance(feet, inches);
}
};
int main() { Output:
Distance D1(11, 10), D2(-5, 11);
-D1; // apply negation
D1.displayDistance(); // display D1
F: -11 I:-10
F: 5 I:-11
-D2; // apply negation
D2.displayDistance(); // display D2
return 0;
}
// C++ program to show binary operator overloading using a Friend Function
#include <iostream>
using namespace std;
class Distance {
Binary operator overloading
public:
int feet, inch;
using Friend Function
Distance()
{
this->feet = 0;
this->inch = 0;
}
Distance(int f, int i)
{
this->feet = f;
this->inch = i;
}
// Declaring friend function using friend keyword
friend Distance operator + (Distance&, Distance&);
};
// Implementing friend function with two parameters Call by reference
Distance operator+(Distance& d1, Distance& d2)
{
Distance d3;
d3.feet = d1.feet + d2.feet;
d3.inch = d1.inch + d2.inch;
return d3;
}
int main()
{
Distance d1(8, 9);
Distance d2(10, 2);
Distance d3;
// Use overloaded operator Output
d3 = d1 + d2; Total Feet & Inches: 18'11
cout << "\nTotal Feet & Inches: " << d3.feet << "'" << d3.inch;
return 0;
}
Note
• Operator overloading cannot be used to change the way
operator works on built-in types. Operator overloading
only allows redefining the meaning of operator for user-
defined types.
• There are two operators assignment operator(=) and
address operator(&) which does not need to be
overloaded. Because these two operators are already
overloaded in the C++ library.
• For example: If obj1 and obj2 are two objects of the same
class then, you can use code obj1=obj2; without
overloading the = operator. This code will copy the
contents object of obj2 to obj1.
• Similarly, you can use the address operator directly
without overloading which will return the address of the
object in memory.
• Operator overloading cannot change the precedence
14
Rules For Overloading
• The following operators can be overloaded with the
use of member functions and not by the use of friend
functions:
• Assignment operator =
• Function call operator( )
• Subscripting operator [ ]
• Class member access operator ->
• Unary operators,
• overloaded by means of a member function, take no
explicit arguments and return no explicit values,
• overloaded by means of a friend function, take one
28
reference argument.
Rules For Overloading
• Binary operators
• overloaded through a member function, take one
explicit argument and those which are
• overloaded through a friend function, takes two
explicit arguments.
• When using binary operators overloaded through a
member function, the left-hand operand must be an
object of the relevant class.
• Binary arithmetic operators such as +, -, * and / must
explicitly return a value. They must not attempt to
change their own arguments.
Polymorphism
• Polymorphism is an important concept of
the Object-oriented programming
paradigm.
• It can be classified in two ways on the
basis of the time at which the procedure
call is resolved.
• Static Polymorphism
• Dynamic Polymorphism
Static & Dynamic Polymorphism
• Static Polymorphism implies that the invocation (call)
to a function is resolved at compile time. It can be
implemented using Overloading.
– It is also called early binding or compile-time polymorphism
• Dynamic Polymorphism implies that the invocation
(call) to a function is resolved at run time. In dynamic
polymorphism, the compiler resolves the object at run time
and then it decides which function call should be associated
with that object.
– It is also called late binding or run-time polymorphism. This type of
polymorphism is executed through virtual functions and function
overriding.
Virtual Function
• For the overriding, the function should be
bound dynamically to the function body, we
make the base class function virtual using the
“virtual” keyword.
• This virtual function is a function that is
overridden in the derived class and the
compiler carries out late or dynamic binding
for this function.
Virtual Function: Early/Late binding
//Early Binding // Late binding
#include<iostream> #include<iostream>
using namespace std; using namespace std;
class A { class A {
public: public:
void show(){ virtual void show(){
cout<<"base class"<<endl;
cout<<"base class"<<endl;
}
}
};
};
class B:public A{
class B:public A{
public:
public:
void show(){
void show(){ cout<<"derived class"<<endl;
cout<<"derived class"<<endl; }
} };
}; int main(){
int main(){ A *bptr; // base class ptr
B b; B b; // derived class object
b.show(); // early binding (at compile time) bptr=&b; // base class ptr referencing derived class object
b.A::show(); // early binding bptr->show(); // late binding (at run time)
return 0; return 0;
} }
Output: Output:
derived class derived class
base class
• A virtual function is redefined in the derived class.
• When a virtual function is defined in the base class, then the pointer to base
class is created. Now, on the basis of type of object assigned, the respective
class function will be called.
So in this class definition of Base, we made the show() function as “virtual”. As the base
class function is made virtual, when we assign the derived class object to the base class
pointer and call the show() function, the binding happens at runtime.
Thus, as the base class pointer contains a derived class object, the show() function body
in the derived class is bound to function show() and hence the output.
• In C++, the overridden function in derived class
can also be private. The compiler only checks
the type of the object at compile time and
binds the function at run time, hence it
doesn’t make any difference even if the
function is public or private.
• Note that if a function is declared virtual in the
base class, it will be virtual in all derived
classes.
Pure Virtual Function
#include<iostream>
using namespace std;
class A {
public:
virtual void show()=0; // pure virtual function
};
class B:public A{
public:
void show(){
cout<<"derived class"<<endl;
}
};
int main(){
A *bptr;
B b;
bptr=&b;
bptr->show(); // late binding (at run time)
return 0;
}
Output:
derived class
Pure Virtual Functions and Abstract Classes
• Sometimes implementation of all functions cannot be
provided in a base class because we don’t know the
implementation. Such a class is called an abstract class.
• For example, let Shape be a base class. We cannot
provide an implementation of function draw() in the
Shape class, but we know every derived class must
have an implementation of draw().
• We cannot create objects of abstract classes.
• A pure virtual function is implemented by classes that
are derived from an Abstract class.
• A pure virtual function (or abstract function) in C++ is a virtual
function for which we can have an implementation
• But we must override that function in the derived class,
otherwise the derived class will also become an abstract class.
• A pure virtual function is declared by assigning 0 in the
declaration.
• A class is abstract if it has at least one pure virtual function.
• We can have pointers and references of abstract class type.
• An abstract class can have constructors.
example
#include<iostream>
using namespace std;
class Base
{
int x;
public:
virtual void fun() = 0;
int getX() { return x; }
};
// This class inherits from
//Base and implements fun()
class Derived: public Base
{
int y;
public:
void fun() { cout << "fun() called"; }
};
int main(void)
{
Derived d;
d.fun();
return 0;
}
Output:
fun() called