C++ Polymorphism
The word “polymorphism” means having many forms. In
simple words, we can define polymorphism as the ability of a
message to be displayed in more than one form.
A real-life example of polymorphism is a person who at the
same time can have different characteristics. A man at the
same time is a father, a husband, and an employee. So the
same person exhibits different behavior in different situations.
This is called polymorphism.
Types of Polymorphism
Compile-time Polymorphism
Runtime Polymorphism
1. Compile-Time Polymorphism
This type of polymorphism is achieved by function overloading
or operator overloading.
A. Function Overloading
When there are multiple functions with the same name but
different parameters, then the functions are said to
be overloaded, hence this is known as Function Overloading.
Functions can be overloaded by changing the number of
arguments or/and changing the type of arguments. In
simple terms, it is a feature of object-oriented programming
providing many functions that have the same name but distinct
parameters when numerous tasks are listed under one
function name.
1. class A // base class declaration.
2. {
3. int a;
4. public:
5. void display()
6. {
7. cout<< "Class A ";
8. }
9. };
10. class B : public A // derived class declarati
on.
11. {
12. int b;
13. public:
14. void display()
15. {
16. cout<<"Class B";
17. }
18. };
B. Operator Overloading in C++
C++ has the ability to provide the operators with a special
meaning for a data type, this ability is known as operator
overloading.
Operator overloading is a compile-time polymorphism. For
example, we can overload an operator ‘+’ in a class like
String so that we can concatenate two strings by just
using +. Other example classes where arithmetic operators
may be overloaded are Complex Numbers, Fractional
Numbers
Syntax of Operator Overloading
1. return_type class_name : : operator op(argument_list)
2. {
3. // body of the function.
4. }
Where the return type is the type of value returned by the
function.
class_name is the name of the class.
operator op is an operator function where op is the operator
being overloaded, and the operator is the keyword.
Rules for Overloading Operators in C++:
1.Operators Cannot be Overloaded for Built-in Types:
You can't overload operators for built-in types like int, float, etc.
Overloading is only possible for user-defined types (classes
and structures).
2. Arity Cannot be Changed:
You can't change the number of operands an operator takes.
For example, you can't make the addition operator (+) work
with only one operand.
3.Precedence and Associativity Cannot be Changed:
Overloaded operators maintain their precedence and
associativity, so you can't change how operators are grouped
or ordered.
Overloaded Operators Must Have At Least One User-Defined
Type:
At least one operand of the overloaded operator must be a
user-defined type (a class or a structure).
4.Some Operators Can't be Overloaded:
Certain operators like . (dot), .*, ::, ?:, sizeof, and typeid cannot
be overloaded.
5.Overloading does not Change the Meaning of Operators:
Overloading operators does not change the meaning of
operators for built-in types or existing classes. The behavior of
overloaded operators should be intuitive and consistent with the
operator's traditional meaning.
6.Overloaded Operators Can be Member Functions or
Global Functions:
You can overload operators as member functions or global
functions. Member functions affect the left operand, while
global functions require at least one parameter of a user-
defined type.
Remember, while operator overloading can make code more
readable and expressive, it should be used judiciously to avoid
confusion and maintain code clarity.
Overloading of Unary operators
#include<iostream>
using namespace std;
class A{
public:
int x = 10;
void operator ++(){
x = x + 5;
}
};
int main(){
A obj;
cout<<obj.x<<endl;
++obj;
cout<<obj.x<<endl;
return 0;
}
Overloading of Binary operators
#include <iostream>
using namespace std;
class Number {
public:
int value;
Number(int val) : value(val) {}
Number operator+(const Number& other) {
Number result(value + other.value);
return result;
}
};
int main() {
Number num1(5);
Number num2(10);
Number sum = num1 + num2;
cout << "Sum: " << sum.value << endl;
return 0;
}
2. Runtime Polymorphism
This type of polymorphism is achieved by Function
Overriding. Late binding and dynamic polymorphism are other
names for runtime polymorphism. The function call is resolved
at runtime in runtime polymorphism.
In contrast, with compile time polymorphism, the compiler
determines which function call to bind to the object after
deducing it at runtime.
A. Function Overriding
Function Overriding occurs when a derived class has a
definition for one of the member functions of the base class.
That base function is said to be overridden.
In function overriding, we have two definitions of the same
function, one in the superclass and one in the derived class.
The decision about which function definition requires calling
happens at runtime. That is the reason we call it ‘Runtime
polymorphism’.
#include <iostream>
using namespace std;
class Animal {
public:
void function(){
cout<<"Eating..."<<endl;
}
};
class Man: public Animal
{
public:
void function()
{
cout<<"Walking ..."<<endl;
}
};
int main(void) {
Man m = Man();
m.function(); // child class object
return 0;
}
Output
Walking……
B. Virtual Function
A virtual function is declared by keyword virtual. The return type
of virtual function may be int, float, void.
A virtual function is a member function in the base class. We
can redefine it in a derived class. It is part of run time
polymorphism. The declaration of the virtual function must be in
the base class by using the keyword virtual. A virtual function is
not static.
The virtual function helps to tell the compiler to perform
dynamic binding or late binding on the function.
If it is necessary to use a single pointer to refer to all the
different classes’ objects. This is because we will have to
create a pointer to the base class that refers to all the derived
objects.
But, when the base class pointer contains the derived class
address, the object always executes the base class function.
For resolving this problem, we use the virtual function.
When we declare a virtual function, the compiler determines
which function to invoke at runtime.
#include<iostream>
using namespace std;
class Add
{
public:
virtual void print ()
{
cout<< " base class Action is:" <<endl;
}
};
class Sub: public Add
{
public:
void print ()
{
cout<< " derived class Action:" <<endl; }
};
int main()
{
Add *ptr;
Sub s;
ptr = &s;
ptr->print();
return 0;
}
Output
derived class Action:
Pure Virtual Function
When the function has no definition, we call such functions as
“Do-nothing function or Pure virtual function”. The declaration of
this function happens in the base class with no definition.
Source Code
1 #include <iostream>
2 using namespace std;
3 class Animal
4 {
5 public:
6 virtual void show() = 0; //Pure virtual function declaration.
7 };
8 class Man: public Animal
9 {
10 public:
11 void show()
12 {
13 cout << "Man is the part of animal husbandry " << endl;
14 }
15 };
16 int main()
17 {
18 Animal *ptr;
19 Man m;
20 ptr = &m;
21 ptr->show();
22 return 0;
23 }
24