9. Polymorphism
9. Polymorphism
Introduction
• Polymorphism is one of the crucial features of OOP. It simply means
‘one name, multiple forms ’.
• It is of two types- compile time polymorphism and run time
polymorphism.
• Compile time polymorphism is implemented using the overloaded
functions and operators, where the overloaded member functions are
selected for invoking by matching arguments, both type and number.
• This information is known to the compiler at the compile time and,
therefore, compiler is able to select the appropriate function for a
particular call at the compile time itself.
• This is called early binding or static binding or static linking.
• Consider a situation where the function name and prototype is the same in
both the base and derived classes as shown below:
class A
{
int x;
public:
void show() {…..} //show () in base class
};
class B: public A
{ int y;
public:
void show () {…..} //show () in derived class
};
• Since the prototype is the same in both the classes, the function is not
overloaded and therefore static binding does not apply.
• Earlier, in such situations, class resolution operator may be used to specify the
class while invoking the functions with the derived class objects.
• In such situations, it would be better if the appropriate member function could
be selected while the program is running. This is known as run time
polymorphism.
• C++ supports a mechanism known as virtual function to achieve run time
polymorphism.
• At run time, when it is known what class objects are under consideration, the
appropriate version of the function is invoked.
• Since the function is linked with a particular class much later after the
compilation, this process is termed as late binding. It is also known as dynamic
binding as the selection of the appropriate function is done dynamically at run
time.
Pointers
• A pointer is a derived data type that refers to another data variable by storing
the variable’s memory address rather than data.
• The declaration of a pointer variable takes the following form:
data-type *pointer-variable;
• Consider the following declaration:
int *ptr;
• Here, ptr is a pointer variable that points to an integer data type. The pointer
variable ptr should contain the memory location of any integer variable.
• We can initialize a pointer variable as follows:
int *ptr, a; //declaration
ptr = &a; //initialization
• We can also declare a pointer variable to point to another pointer.
// example of using pointers Output:
#include<iostream> The address of a: 0x8fb6fff4
Using namespace std; The address of ptr1: 0x8fb6ff2
void main() Ater incrementing the address values:
{ The address of a: 0x8fb6fff8
The address of ptr1: 0x8fb6ff6
int a, *ptr1, **ptr2;
ptr1 = &a;
ptr2 = &ptr1;
cout<<“The address of a: ”<<ptr1<<“\n”;
cout<<“The address of ptr1: ”<<ptr2;
cout<<“\n\n”;
cout<< “After incrementing the address values:\n\n”;
ptr1+ = 2;
cout<<“The address of a: ”<<ptr1<<“\n”;
ptr2+ = 2;
cout<<“The address of ptr1: ”<<ptr2<<“\n”;
}
Manipulation of Pointers
• We can manipulate a pointer with the indirection operator, i.e., ‘*’,
which is also known as dereference operator.
• The data variable contents can be accessed indirectly using this
operator. It takes the general form:
*pointer_variable
• After assigning address of the variable to a pointer, we can change the
contents of the memory location using the dereference operator.
// example of manipulation of pointers
#include<iostream>
using namespace std;
void main()
{
int a =10, *ptr;
ptr = &a;
cout<<“The value of a is: ”<<a;
cout<<“\n\n”;
*ptr = (*ptr)/2;
cout<<“The value of a is: ”<< (*ptr); Output:
The value of a is: 10
cout<<“\n\n”; The value of a is: 5
}
Pointer Expressions and Pointer
Arithmetic
• C++ allows pointers to perform the following arithmetic operations:
• A pointer can be incremented (++) or decremented (--)
• Any integer can be added to or subtracted from a pointer
• One pointer can be subtracted from another
• Example:
int a[6];
int *aptr;
aptr = &a[0];
• The pointer variable, aptr, refers to the base address of the variable a. the pointer variable
can be incremented as shown:
aptr++ or ++aptr
• This statement moves the pointer to the next memory address. Similarly, a pointer variable
can be decremented as follows:
aptr-- or –aptr
• This statement moves the pointer to the previous memory address.
// Arithmetic Operations on Pointers
#include<iostream>
using namespace std;
void main()
{
int num[] = {56, 75, 22, 18, 90};
int *ptr, i;
cout<<“The array values are:\n ”;
for(i=0; i<5; i++)
cout<<num[i]<<“\n”;
ptr = num;
cout<<“\nValue of ptr: ”<<*ptr;
cout<<“\n”;
ptr++;
cout<<“\nValue of ptr++: ”<<*ptr;
cout<<“\n”;
ptr--;
cout<<“\nValue of ptr--: ”<<*ptr;
cout<<“\n”;
ptr = ptr + 2;
cout<<“\nValue of ptr + 2: ”<<*ptr;
cout<<“\n”;
ptr = ptr - 1;
cout<<“\nValue of ptr - 1: ”<<*ptr;
cout<<“\n”; Output:
The value of a is: 10
ptr++; The value of a is: 5
cout<<“\nValue of ptr+ = 3: ”<<*ptr;
cout<<“\n”;
ptr- = 2; Output:
cout<<“\nValue of ptr- = 2: ”<<*ptr; The array values are:
56
cout<<“\n”; 75
ptr = ptr + 2; 22
18
cout<<“\nValue of ptr + 2: ”<<*ptr; 90
cout<<“\n”; Value of ptr: 56
Value of ptr++: 75
return 0; Value of ptr--: 56
} Value of ptr+ 2: 22
Value of ptr - 1: 75
Value of ptr+ = 3: 90
Value of ptr- = 2: 22
Pointers with Arrays
#include<iostream>
using namespace std;
int main()
{
int numbers[50], *ptr;
int n, i;
cout<<“\nEnter the count\n”;
cin>>n;
cout<<“\nEnter the numbers one by one\n”;
for(i=0; i<n; i++)
cin>>numbers[i];
ptr = numbers;
int sum = 0;
/*Check out for even inputs and sum them up */
for(i=0; i<n; i++)
{ Output:
Enter the count
if (*ptr%2 == 0) 5
sum = sum +*ptr; Enter the numbers one by one
10
ptr++; 16
} 23
45
cout<<“\n\nSum of even numbers:”<<sum; 34
return 0; Sum of even numbers: 60
}
Array of Pointers
• Similar to other variables, array of pointers can be created in C++.
• An array of pointers point to an array of data items. Each element of
the pointer array points to an item of the data array.
• Data items can be accessed either directly or by dereferencing the
elements of pointer array.
• Array of pointers can be declared as follows:
int *inarray[10];
• The above statement declares an array of 10 pointers, each of which
points to an integer. The address of the first pointer is inarray[0], that
of second is inarray[1] and the final array points to inarray[9].
// Arrays of Pointers
#include<iostream>
#include<string.h>
using namespace std;
int main()
{ int i = 0;
char *ptr[10] = { “books”,
“television”,
“computer”,
“sports” };
char str[25];
cout<<“\nEnter your favourite leisure pursuit:” ;
cin>>str;
for(i=0; i<4; i++)
{
if(!strcmp(str, *ptr[i]))
{
cout<<“\nYour favourite pursuit is available here”<<endl;
break;
}}
if(i==4)
cout<<“\nYour favourite pursuit” << “is not available here”<<endl;
return 0;
}
Pointers and Strings
• In C++, a string is one-dimensional array of characters, which starts
with the index 0 and ends with the null character ‘\0’.
• A pointer variable can access a string by referring to its first character.
• There are two ways to assign a value to a string- using a character
array or using a variable of type char *as shown below:
char num[] = “one”;
const char *numptr = “one”;
• The first declaration creates an array of four characters, which
contains the characters, ‘o’, ‘n’, ‘e’, ‘\0’, whereas the second
declaration generates a pointer variable, which points to the first
character of the string.
//Accessing strings using pointers and arrays
#include<iostream>
#include<string.h>
int main()
{
char str[] = “Test”;
int len = strlen(str);
for(int i=0; i<len; i++)
{
cout<<str[i]<<i[str]<<*(str+i)<<*(i+str);
}
cout<<endl;
//String reverse
int lenM = len/2;
len--;
for(i=0; i<lenM; i++)
{
str[i] = str[i] + str[len-i];
str[len-i] = str[i] - str[len-i];
str[i] = str[i] - str[len-i];
}
cout<<“The string reversed: ” << str; Output :
return 0; TTTTeeeesssstttt
The string reversed : tseT
}
Pointers to Objects
• A pointer can point to an object created by a class. Consider the
following statement:
item x;
where item is a class and x is an object defined to be of type item.
Similarly, a pointer it_prt of type item can be defined as follows:
item *it_ptr;
• Object pointers are useful in creating objects at run time. They can
also be used to access public members of an object. Consider a class
item defined as follows:
#include<iostream>
using namespace std;
class item
{
int code;
float price;
public:
void getdata(int a, int b)
{
code = a;
price = b;
}
void show(void)
{
cout<<“Code: ”<<code<<“\n”;
cout<<“ Price: ”<<price<<“\n\n”;
} };
const int size = 2;
int main()
{
item *p = new item[size];
item *d = p;
int x, i;
float y;
for(i=0; i<size; i++)
{
cout<<“Input code and price for item”<<i+1;
cin>>x>>y;
p->getdata(x,y);
p++;
}
for(i=0; i<size; i++) Output:
{ Input code and price for Item1 40 500
Input code and price for item2 50 600
cout<<“Item: ”<<i+1<<“\n”; Item: 1
d->show(); Code: 40
d++; Price: 500
Item: 2
} Code: 50
return 0; Price: 600
}
• Here, we created space dynamically for two objects of equal size, but this
may not be the case always.
• For example, the objects of a class that contain character strings would
not be of the same size. In such cases, we can define an array of pointers
to objects that can be used to access individual objects.
//Array of Pointers to Objects
#include<iostream>
#include<cstring>
using namespace std;
class city
{
protected:
char *name;
int len;
public:
city()
{
len =0;
name = new char[len + 1];
}
void getname(void)
{
char *s;
s = new char[30];
cout<<“Enter city name:”;
cin>>s;
len = strlen(s);
name = new char[len + 1];
strcpy(name, s);
}
void printname(void)
{ cout<< name <<“\n”; }
};
int main()
{
city *cptr[10];
int n = 1, option;
do {
cptr[n] = new city;
cptr[n]->getname();
n++;
cout<<“Do you want to enter one or more name?\n”;
cout<<“(Enter 1 for yes 0 for no):”;
cin>>option;
} while (option);
cout<<“\n\n”;
for(int i=1; i<=n; i++)
{
cptr[i]->printname();
Output:
} Enter city name: Hyderabad
return 0; Do you want to enter one more name?
} (Enter 1 for yes 0 for no): 1
Enter city name: Secunderabad
Do you want to enter one more name?
(Enter 1 for yes 0 for no): 0
Hyderabad
Secunderabad
Pointer to Derived Classes
• Pointers can be used for base class objects as well as
objects of derived classes.
• A pointer to the object of the derived class and a pointer
to the object of the base class are type-compatible.
• It is possible to declare a pointer , which points to the
base class as well as the derived class.
• One pointer can point to different classes.
• A base class pointer can point to a derived class object
in C++, but we can only access base class members
using the base class pointer.
#include<iostream>
using namespace std;
class BaseClass{
public:
int var_base;
void display(){
cout<<"Dispalying Base class variable var_base "<<var_base<<endl;
}
};
class DerivedClass : public BaseClass{
public:
int var_derived;
void display(){
cout<<"Dispalying Base class variable var_base "<<var_base<<endl;
cout<<"Dispalying Derived class variable var_derived "<<var_derived<<endl;
}
};
int main()
{
BaseClass * base_class_pointer;
BaseClass obj_base;
DerivedClass obj_derived;
base_class_pointer = &obj_derived; // Pointing base class pointer to derived class
base_class_pointer->var_base = 34;
// base_class_pointer->var_derived= 134; // Will throw an error
base_class_pointer->display();
base_class_pointer->var_base = 3400;
base_class_pointer->display();
DerivedClass * derived_class_pointer; Output:
derived_class_pointer = &obj_derived;
derived_class_pointer->var_base = 9448;
derived_class_pointer->var_derived = 98;
derived_class_pointer->display();
return 0;
}
VIRTUAL FUNCTION
• A C++ virtual function is a member function in the base class that you redefine
in a derived class. It is declared using the virtual keyword.
• It is used to tell the compiler to perform dynamic linkage or late binding on
the function.
• There is a necessity to use the single pointer to refer to all the objects of the
different classes. So, we create the pointer to the base class that refers to all
the derived objects. But, when base class pointer contains the address of the
derived class object, always executes the base class function. This issue can
only be resolved by using the 'virtual' function.
• A 'virtual' is a keyword preceding the normal declaration of a function.
• When the function is made virtual, C++ determines which function is to be
invoked at the runtime based on the type of the object pointed by the base
class pointer.
RULES FOR VIRTUAL FUNCTION
• Virtual functions must be members of some class.
• Virtual functions cannot be static members.
• They are accessed through object pointers.
• They can be a friend of another class.
• A virtual function must be defined in the base class, even though it is not used.
• The prototypes of a virtual function of the base class and all the derived classes
must be identical. If the two functions with the same name but different
prototypes, C++ will consider them as the overloaded functions.
• We cannot have a virtual constructor, but we can have a virtual destructor
• Consider the situation when we don't use the virtual keyword.
Example
#include <iostream>
using namespace std;
class A
{
public:
virtual void display()
{
cout << "Base class is invoked"<<endl;
}
};
class B:public A
{
public:
void display()
{
cout << "Derived Class is invoked"<<endl;
}
};
CONTD..
Derived class is derived from the base class.
int main()
{
A* a; //pointer of base class
A a1;
B b; //object of derived class
a = &b;
a->display(); //Late Binding occurs
a= &a1;
a->display();
}
Output:
Derived Class is invoked
Base Class is invoked
PURE VIRTUAL FUNCTION
• A virtual function is not used for performing any task. It only serves as a placeholder.
• When the function has no definition, such function is known as "do-nothing"
function.
• The "do-nothing" function is known as a pure virtual function. A pure virtual
function is a function declared in the base class that has no definition relative to the
base class.
• A class containing the pure virtual function cannot be used to declare the objects of
its own, such classes are known as abstract base classes.
• The main objective of the base class is to provide the traits to the derived classes
and to create the base pointer used for achieving the runtime polymorphism.
• Pure virtual function can be defined as:
virtual void display() = 0;
EXAMPLE
#include <iostream>
using namespace std;
class Base
{
public:
virtual void show() = 0;
};
class Derived : public Base
{
public:
void show()
{
cout << "Derived class is derived from the base class." << endl;
}
};
int main()
{
Base *bptr;
//Base b;
Derived d;
bptr = &d;
bptr->show();
return 0;
}
Output: