Nothing Special   »   [go: up one dir, main page]

Polymorphism

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 19

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.
Real life example of polymorphism, a person at the same time can have
different characteristic. Like a man at the same time is a father, a husband, an
employee. So the same person posses different behavior in different
situations. This is called polymorphism.
Polymorphism is considered as one of the important features of Object
Oriented Programming.

In C++ polymorphism is mainly divided into two types:


 Compile time Polymorphism
 Runtime Polymorphism
1. Compile time polymorphism: This type of polymorphism is achieved by
function overloading or operator overloading.

 Function Overloading: When there are multiple functions with same


name but different parameters then these functions are said to
be overloaded. Functions can be overloaded by change in number of
arguments or/and change in type of arguments
#include <bits/stdc++.h>
using namespace std;
class Geeks
{
public:
// function with 1 int parameter
void func(int x)
{
cout << "value of x is " << x << endl;
}
// function with same name but 1 double parameter
void func(double x)
{
cout << "value of x is " << x << endl;
}
// function with same name and 2 int parameters
void func(int x, int y)
{
cout << "value of x and y is " << x << ", " << y << endl;
}
};
int main() {

Geeks obj1;
// Which function is called will depend on the parameters passed
// The first 'func' is called
obj1.func(7);
// The second 'func' is called
obj1.func(9.132);
// The third 'func' is called
obj1.func(85,64);
return 0;
}
Rules of Function Overloading

Functions that cannot be overloaded in C++


1) Function declarations that differ only in the return type. For example, the
following program fails in compilation.

#include<iostream>
int foo() {
return 10;
}

char foo() {
return 'a';
}

int main()
{
char x = foo();
getchar();
return 0;
}

2) Member function declarations with the same name and the name parameter-
type-list cannot be overloaded if any of them is a static member function
declaration. For example, following program fails in compilation.

#include<iostream>
class Test {
static void fun(int i) {}
void fun(int i) {}
};

int main()
{
Test t;
getchar();
return 0;

}
3) Parameter declarations that differ only in a pointer * versus an array [] are
equivalent. That is, the array declaration is adjusted to become a pointer
declaration. Only the second and subsequent array dimensions are significant
in parameter types. For example, following two function declarations are
equivalent.

int fun(int *ptr);


int fun(int ptr[]); // redeclaration of fun(int *ptr)
4) Parameter declarations that differ only in that one is a function type and the
other is a pointer to the same function type are equivalent.

void h(int ());


void h(int (*)()); // redeclaration of h(int())
5) Parameter declarations that differ only in the presence or absence of const
and/or volatile are equivalent. That is, the const and volatile type-specifiers for
each parameter type are ignored when determining which function is being
declared, defined, or called. For example, following program fails in
compilation with error “redefinition of `int f(int)’ “
Example:

#include<iostream>
#include<stdio.h>

using namespace std;

int f ( int x) {
return x+10;
}

int f ( const int x) {


return x+10;
}

int main() {
getchar();
return 0;
}
Only the const and volatile type-specifiers at the outermost level of the
parameter type specification are ignored in this fashion; const and volatile
type-specifiers buried within a parameter type specification are significant and
can be used to distinguish overloaded function declarations. In particular, for
any type T,
“pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered
distinct parameter types, as are “reference to T,” “reference to const T,” and
“reference to volatile T.” For example, see the example in this comment posted
by Venki.
6) Two parameter declarations that differ only in their default arguments are
equivalent. For example, following program fails in compilation with
error “redefinition of `int f(int, int)’ “

#include<iostream>
#include<stdio.h>

using namespace std;

int f ( int x, int y) {


return x+10;
}

int f ( int x, int y = 10) {


return x+y;
}

int main() {
getchar();
return 0;
}

Operator Overloading: C++ also provide option to overload operators. For


example, we can make the operator (‘+’) for string class to concatenate two
strings. We know that this is the addition operator whose task is to add two
operands. So a single operator ‘+’ when placed between integer operands ,
adds them and when placed between string operands, concatenates them.
Example:

// CPP program to illustrate


// Operator Overloading
#include<iostream>
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 << endl; }
};
int main()
{
Complex c1(10, 5), c2(2, 4);
Complex c3 = c1 + c2; // An example call to "operator+"
c3.print();
}
Output:
12 + i9

How to overload operators in C++ programming?


To overload an operator, a special operator function is defined inside the class as:
class className

... .. ...

public

returnType operator symbol (arguments)

... .. ...

... .. ...

};

 Here, returnType is the return type of the function.


 The returnType of the function is followed by operator keyword.
 Symbol is the operator symbol you want to overload. Like: +, <, -, ++
 You can pass arguments to the operator function in similar way as functions.

Example: Operator overloading in C++


Programming
1. #include <iostream>
2. using namespace std;
3.
4. class Test
5. {
6. private:
7. int count;
8.
9. public:
10. Test(): count(5){}
11.
12. void operator ++()
13. {
14. count = count+3;
15. }
16. void Display() { cout<<"Count: "<<count; }
17. };
18.
19. int main()
20. {
21. Test t;
22. // this calls "function void operator ++()" function
23. ++t;
24. t.Display();
25.
26. return 0;
27. }

28. Count: 6

#include <iostream>
using namespace std;

class Box {
public:
double getVolume(void) {
return length * breadth * height;
}
void setLength( double len ) {
length = len;
}
void setBreadth( double bre ) {
breadth = bre;
}
void setHeight( double hei ) {
height = hei;
}

// Overload + operator to add two Box objects.


Box operator+(const Box& b) {
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}

private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};

// Main function for the program


int main() {
Box Box1; // Declare Box1 of type Box
Box Box2; // Declare Box2 of type Box
Box Box3; // Declare Box3 of type Box
double volume = 0.0; // Store the volume of a box here

// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);

// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);

// volume of box 1
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;

// volume of box 2
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;

// Add two object as follows:


Box3 = Box1 + Box2;

// volume of box 3
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;

return 0;
}
Virtual Function in C++
A virtual function 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.
Rules for Virtual Functions
1. Virtual functions cannot be static and also cannot be a friend function of another class.
2. Virtual functions should be accessed using pointer or reference of base class type to
achieve run time polymorphism.
3. The prototype of virtual functions should be same in base as well as derived class.
4. They are always defined in base class and overridden in derived class. It is not
mandatory for derived class to override (or re-define the virtual function), in that case
base class version of function is used.
5. A class may have virtual destructor but it cannot have a virtual constructor.
Compile-time(early binding) VS run-time(late binding) behavior of Virtual
Functions
Consider the following simple program showing run-time behavior of virtual
functions.
// CPP program to illustrate

// concept of Virtual Functions

#include<iostream>

using namespace std;

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 ()

{ cout<< "show derived class" <<endl; }

};

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
show base class

Explanation: Runtime polymorphism is achieved only through a pointer (or


reference) of base class type. Also, a base class pointer can point to the objects of
base class as well as to the objects of derived class. In above code, base class
pointer ‘bptr’ contains the address of object ‘d’ of derived class.
Late binding(Runtime) is done in accordance with the content of pointer (i.e. location
pointed to by pointer) and Early binding(Compile time) is done according to the type
of pointer, 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
) and show() is non-virtual so it will be bound during compile time(output is show
base class as pointer is of base type ).
NOTE: If we have created a virtual function in the base class and it is being
overridden in the derived class then we don’t need virtual keyword in the derived
class, functions are automatically considered as virtual functions in the derived class.
Working of virtual functions(concept of VTABLE and VPTR)
As discussed here , If a class contains a virtual function then compiler itself does two
things:
1. 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.
2. 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.
Consider the example below:

// CPP program to illustrate

// working of Virtual Functions

#include<iostream>

using namespace std;

class base

public:

void fun_1() { cout << "base-1\n"; }

virtual void fun_2() { cout << "base-2\n"; }


virtual void fun_3() { cout << "base-3\n"; }

virtual void fun_4() { cout << "base-4\n"; }

};

class derived : public base

public:

void fun_1() { cout << "derived-1\n"; }

void fun_2() { cout << "derived-2\n"; }

void fun_4(int x) { cout << "derived-4\n"; }

};

int main()

base *p;

derived obj1;

p = &obj1;

// Early binding because fun1() is non-virtual

// in base

p->fun_1();

// Late binding (RTP)

p->fun_2();

// Late binding (RTP)

p->fun_3();

// Late binding (RTP)

p->fun_4();

// Early binding but this function call is

// illegal(produces error) becasue pointer

// is of base type and function is of

// derived class

//p->fun_4(5);
}

Output:
base-1
derived-2
base-3
base-4
Explanation: Initially, we create a pointer of type base class and initialize it with the
address of the derived class object. When we create an object of the derived class,
the compiler creates a pointer as a data member of the class containing the address
of VTABLE of the derived class.
Similar concept of Late and Early Binding is used as in above example. For fun_1()
function call, base class version of function is called, fun_2() is overridden in derived
class so derived class version is called, fun_3() is not overridden in derived class
and is virtual function so base class version is called, similarly fun_4() is not
overridden so base class version is called.
NOTE: fun_4(int) in derived class is different from virtual function fun_4() in base
class as prototype of both the function is different.
.
Pure Virtual Functions and 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 must have
implementation of draw(). Similarly an Animal class doesn’t have implementation of
move() (assuming that all animals move), but all animals must know how to move.
We cannot create objects of abstract classes.
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. See the following example.
// An abstract class

class Test

// Data members of class

public:

// Pure Virtual Function

virtual void show() = 0;

/* Other members */

};

A complete example:
A pure virtual function is implemented by classes which are derived from a Abstract
class. Following is a simple example to demonstrate the same.

#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
Some Interesting Facts:
1) A class is abstract if it has at least one pure virtual function.
In the following example, Test is an abstract class because it has a pure virtual
function show().

// pure virtual functions make a class abstract

#include<iostream>

using namespace std;

class Test

int x;

public:

virtual void show() = 0;

int getX() { return x; }

};
int main(void)

Test t;

return 0;

Output:
Compiler Error: cannot declare variable 't' to be of abstract
type 'Test' because the following virtual functions are pure
within 'Test': note: virtual void Test::show()
2) We can have pointers and references of abstract class type.
For example the following program works fine.

#include<iostream>

using namespace std;

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;

Output:
In Derived
3) If we do not override the pure virtual function in derived class, then derived class
also becomes abstract class.
The following example demonstrates the same.

#include<iostream>

using namespace std;

class Base

public:

virtual void show() = 0;

};

class Derived : public Base { };

int main(void)

Derived d;

return 0;

Compiler Error: cannot declare variable 'd' to be of abstract type


'Derived' because the following virtual functions are pure within
'Derived': virtual void Base::show()
4) An abstract class can have constructors.
For example, the following program compiles and runs fine.

#include<iostream>

using namespace std;

// An abstract class with constructor

class Base

protected:

int x;

public:

virtual void fun() = 0;


Base(int i) { x = i; }

};

class Derived: public Base

int y;

public:

Derived(int i, int j):Base(i) { y = j; }

void fun() { cout << "x = " << x << ", y = " << y; }

};

int main(void)

Derived d(4, 5);

d.fun();

return 0;

Output:
x = 4, y = 5

You might also like