What is Polymorphism in C++?

In C++, polymorphism causes a member function to behave differently based on the object that calls/invokes it. Polymorphism is a Greek word that means to have many forms. It occurs when you have a hierarchy of classes related through inheritance.

For example, suppose we have the function makeSound(). When a cat calls this function, it will produce the meow sound. When a cow invokes the same function, it will provide the moow sound.

Though we have one function, it behaves differently under different circumstances. The function has many forms; hence, we have achieved polymorphism.

In this C++ tutorial, you will learn:

Types of Polymorphism

C++ supports two types of polymorphism:

  • Compile-time polymorphism, and
  • Runtime polymorphism.

Compile Time Polymorphism

You invoke the overloaded functions by matching the number and type of arguments. The information is present during compile-time. This means the C++ compiler will select the right function at compile time.

Compile-time polymorphism is achieved through function overloading and operator overloading.

Function Overloading

Function overloading occurs when we have many functions with similar names but different arguments. The arguments may differ in terms of number or type.

Example 1:

#include <iostream> 
using namespace std;

void test(int i) {
	cout << " The int is " << i << endl;
}
void test(double  f) {
	cout << " The float is " << f << endl;
}
void test(char const *ch) {
	cout << " The char* is " << ch << endl;
}

int main() {
	test(5);
	test(5.5);
	test("five");
	return 0;
}

Output:

Here is a screenshot of the code:

Code Explanation:

  1. Include the iostream header file into our code. We will be able to use its functions.
  2. Include the std namespace in our code. We will be able to use its classes without calling it.
  3. Create a function named test that takes an integer parameter i. The { marks the beginning of the body of function test.
  4. Statement to be executed if the above function test is invoked/called.
  5. End of the body of above function test.
  6. Create a function named test that takes a float parameter f. The { marks the beginning of the body of function test.
  7. Statement to be executed if the above function test is invoked/called.
  8. End of the body of the above function test.
  9. Create a function named test that takes a character parameter ch. The { marks the beginning of the body of function test.
  10. Statement to be executed if the above function test is invoked/called.
  11. End of the body of the above function test.
  12. Call the main() function. The { marks the beginning of the body of the function.
  13. Call the function test and passing 5 to it as the value of the argument. This invokes the test function that accepts an integer argument, that is, the first test function.
  14. Call the function test and passing 5.5 to it as the value of the argument. This will invoke the test function that accepts a float argument, that is, the second test function.
  15. Call the function test and passing five to it as the value of the argument. This will invoke the test function that accepts a character argument, that is, the third test function.
  16. The program must return a value if it runs successfully.
  17. The end of the body of the main() function.

We have three functions with the same name but different types of arguments. We have achieved polymorphism.

Operator Overloading

In Operator Overloading, we define a new meaning for a C++ operator. It also changes how the operator works. For example, we can define the + operator to concatenate two strings. We know it as the addition operator for adding numerical values. After our definition, when placed between integers, it will add them. When placed between strings, it will concatenate them.

Example 2:

#include<iostream> 
using namespace std;

class ComplexNum {
private:
	int real, over;
public:
	ComplexNum(int rl = 0, int ov = 0) {
		real = rl;   
		over = ov; 
	}

	ComplexNum operator + (ComplexNum const &obj) {
		ComplexNum result;
		result.real = real + obj.real;
		result.over = over + obj.over;
		return result;
	}
	void print() { 
		cout << real << " + i" << over << endl; 
	}
};
int main()
{
	ComplexNum c1(10, 2), c2(3, 7);
	ComplexNum c3 = c1+c2;
	c3.print();
}

Output:

Here is a screenshot of the code:

Code Explanation:

  1. Include the iostream header file into our program in order to use its functions.
  2. Include the std namespace into our program in order to use its classes without calling it.
  3. Create a class named ComplexNum. The { marks the beginning of the class body.
  4. Use the private access modifier to mark variables as private, meaning they can only be accessed from within the class.
  5. Define two integer variables, real and over.
  6. Use the public access modifier to mark the constructor as public, meaning that it will be accessible even from outside the class.
  7. Create the class constructor and initializing the variables.
  8. Initialize the value of the variable real.
  9. Initialize the value of the variable over.
  10. End of the constructor body.
  11. We need to override the meaning of the + operator.
  12. Create the data type result of type ComplexNum.
  13. Use the + operator with complex numbers. This line will add the real part of a number to the real part of another number.
  14. Use the + operator with complex numbers. This line will add the imaginary part of a number to the imaginary part of another number.
  15. The program will return the value of the variable result upon successful execution.
  16. End of the definition of the new meaning of + operator, that is, overloading.
  17. Call the print() method.
  18. Print the new complex number after addition on the console.
  19. End of the body of print() function.
  20. End of the body of ComplexNum class.
  21. Call the main() function.
  22. Pass the values of both real and complex parts to be added. The first part of c1 will be added to the first part of c2, that is, 10+3. The second part of c1 will be added to the second part of c, that is, 2+7.
  23. Perform an operation using the overloaded + operator and storing the result in variable c3.
  24. Print the value of variable c3 on the console.
  25. End of the body of main() function.

Runtime Polymorphism

This happens when an object's method is invoked/called during runtime rather than during compile time. Runtime polymorphism is achieved through function overriding. The function to be called/invoked is established during runtime.

Function Overriding

Function overriding occurs when a function of the base class is given a new definition in a derived class. At that time, we can say the base function has been overridden.

For example:

#include <iostream>
using namespace std;
class Mammal {

public:
	void eat() {

		cout << "Mammals eat...";
	}

};

class Cow: public Mammal {

public:
	void eat() {

		cout << "Cows eat grass...";
	}
};
int main(void) {

	Cow c = Cow();

	c.eat();

	return 0;

}

Output:

Here is a screenshot of the code:

Code Explanation:

  1. Import the iostream header file into our program to use its functions.
  2. Include the std namespace into our program in order to use its classes without calling it.
  3. Create a class named Mammal. The { marks the beginning of the class body.
  4. Use the public access modifier to set the function we are about to create as publicly accessible. It will be accessible from outside this class.
  5. Create a public function named eat. The { marks the beginning of the function body.
  6. Print the statement added to the cout function when the function eat() is invoked.
  7. The end of the body of function eat().
  8. End of the body of the class Mammal.
  9. Create a class named Cow that inherits the Mammal class. Cow is the derived class, while Mammal is the base class. The { marks the beginning of this class.
  10. Use the public access modifier to mark the function we are about to create as publicly accessible. It will be accessible from outside this class.
  11. Override the function eat() that was defined in the base class. The { marks the beginning of the function body.
  12. The statement to print on the console when this function is invoked.
  13. End of the body of the function eat().
  14. End of the body of the class Cow.
  15. Call the main() function. The { marks the beginning of the body of this function.
  16. Create an instance of the Cow class and giving it the name c.
  17. Call the eat() function defined in the Cow class.
  18. The program must return a value upon successful completion.
  19. End of the main() function.

C++ Virtual Function

A virtual function is another way of implementing run-time polymorphism in C++. It is a special function defined in a base class and redefined in the derived class. To declare a virtual function, you should use the virtual keyword. The keyword should precede the declaration of the function in the base class.

If a virtual function class is inherited, the virtual class redefines the virtual function to suit its needs. For example:

#include <iostream>  
using namespace std;
class ClassA {
		public:
		virtual void show() {
			cout << "The show() function in base class invoked..." << endl;
		}
	};
	class ClassB :public ClassA {
	public:
		void show() 	{
			cout << "The show() function in derived class invoked...";
		}
	};
	int main() {
		ClassA* a;   
		ClassB b;
		a = &b;
		a->show();      
	}

Output:

Here is a screenshot of the code:

Code Explanation:

  1. Include the iostream header file in the code to use its functions.
  2. Include the std namespace in our code to use its classes without calling it.
  3. Create a class named ClassA.
  4. Use the public access modifier to mark a class member as publicly accessible.
  5. Create a virtual function named show(). It will be a public function.
  6. The text to print when the show() invoked is invoked. The endl is a C++ keyword, which means end line. It moves the mouse cursor to the next line.
  7. End of the body of the virtual function show().
  8. End of the body of the class ClassA.
  9. Creating a new class named ClassB that inherits the class ClassA. ClassA becomes the base class while ClassB becomes the derived class.
  10. Use the public access modifier to mark a class member as publicly accessible.
  11. Redefine the virtual function show() derived in the base class.
  12. The text to print on the console when the show() function defined in the derived class is invoked.
  13. End of the body of the show() function.
  14. End of the body of the derived class, ClassB.
  15. Call the main() function. The program logic should be added within its body.
  16. Create a pointer variable named a. It points to the class named ClassA.
  17. Create an instance of the class named ClassB. The instance is given the name b.
  18. Assign the values stores in the address b in the variable a.
  19. Invoke the show() function defined in the derived class. Late binding has been implemented.
  20. End of the body of the main() function.

Compile-Time Polymorphism Vs. Run-Time Polymorphism

Here are the major differences between the two:

Compile-time polymorphism Run-time polymorphism
It's also called early binding or static polymorphism It's also called late/dynamic binding or dynamic polymorphism
The method is called/invoked during compile time The method is called/invoked during run time
Implemented via function overloading and operator overloading Implemented via method overriding and virtual functions
Example, method overloading. Many methods may have similar names but different number or types of arguments Example, method overriding. Many methods may have a similar name and the same prototype.
Faster execution since the methods discovery is done during compile time Slower execution since method discoverer is done during runtime.
Less flexibility for problem-solving is provided since everything is known during compile time. Much flexibility is provided for solving complex problems since methods are discovered during runtime.

Summary:

  • Polymorphism means to have many forms.
  • It occurs when there is a hierarchy of classes related through inheritance.
  • With polymorphism, a function can behave differently based on the object that invokes/calls it.
  • In compile-time polymorphism, the function to be invoked is established during compile-time.
  • In runtime polymorphism, the function to be invoked is established during runtime.
  • Compile-time polymorphism is determined through function overloading and operator overloading.
  • In function overloading, there are many functions with similar names but different arguments.
  • The parameters can differ in number or type.
  • In operator overloading, a new meaning is defined for C++ operators.
  • Runtime polymorphism is achieved through function overriding.
  • In function overriding, a derived class gives a new definition to a function defined in the base class.

 

YOU MIGHT LIKE: