Select Page

You’ll find the term “polymorphism” in various fields and contexts, but its root meaning remains the same. “Poly” means many, and “morphism” details how something has the ability to change. Generically, polymorphism explains how one object or condition can occur in several different forms.

In this article, we discuss how polymorphism works in the context of three key features of the C++ programming language: inheritance, overriding, and overloading. All play a role in polymorphism before seeing its various types in action.

What Is Polymorphism?

A student of C++ needs to know that polymorphism refers to the ability of a C++ function or object to perform in different ways, depending on how the function or object is used. Polymorphism is one of the main features of object-oriented programming.

Polymorphism in C++ allows us to reuse code by creating one function that’s usable for multiple uses. We can also make operators polymorphic and use them to add not only numbers but also combine strings. This saves time and allows for a more streamlined program.

In the example below, see how C++  uses the + operator in two different ways:

...

int main() {
    int num_desserts = 24 + 35;  // + operator used for addition
    cout << num_desserts << endl;
    string str1 = "We can combine strings ";
    string str2 = "that talk about delicious desserts";
    string str = str1 + str2; // + operator used for combining two strings
    cout << str << endl;
    return 0;
}

Depending on context, the + operator can either add two (or more) numbers or combine two strings to form one longer string. We get the following output:

59
We can combine strings that talk about delicious desserts

While a simple example, it shows what polymorphism in C++ can do. But to understand more about how polymorphism works in C++, let’s take a look at inheritance, overloading, and overriding.

C++ Inheritance

The term inheritance implies that some object is taking on, or inheriting, the properties of another object. We often use this term to describe how children have similar features to their parents.

Inheritance in C++ works in much the same way, but with classes. In C++, it’s possible to create a parent class with its own set of functions and variables.

A child (or derived) class, when introduced, inherits those functions and variables to use as its own. Though child classes are a subset of a parent class, they can still have their own specific functions and variables. The diagram below demonstrates this concept:

Dessert represents the parent class, of which Cookie and IceCream are both child classes. The Cookie and IceCream classes inherit the functions and variables of the parent class Dessert but also represent classes of their own.

To see how this plays out in code, take a look at the following example:

class Dessert {  // Here we create the parent class
  public:
    void ingredient() {
        cout << "Desserts have delicious ingredients.";
    }
};

class Cookie: public Dessert { // Here we create a class "Cookie" with Dessert as a parent
  public:
    ...
    }
};

class IceCream: public Dessert { // Here we do the same for a "IceCream" class
  public:
    ...
    }
};

... 

In this code snippet, we introduced the class Dessert with a function called ingredient(), which we’ll revisit. We then created the classes Cookie and IceCream using the Dessert class as a parent. These child classes inherited and were able to use the function as if was their own.

When creating child classes from parents, those child classes can only inherit public and protected data and not anything that is called out as private.

C++ Overriding

Overriding is often seen alongside inheritance in C++. While a child class inherits a function from its parent class, the child class can override the parent class function if it’s redefined in the child class.

See how this works in the code below:

...

class Dessert {  // Parent class
  public:
    void ingredient() {
        cout << "Desserts have delicious ingredients.";
    }
};

class Cookie: public Dessert { // Child class
  public:
    void ingredient() {
        cout << "Cookies are made from flour.";

... 

The Cookie class inherits a function called ingredient(), which has an output of “Desserts have delicious ingredients” in its parent class Dessert. But the parent function is overridden in the Cookie child class because we’ve redefined it with a new output.

C++ Overloading

Overloading in C++ allows us to use one function for different arguments. The code snippet below demonstrates overloading:

...

void output(int dessert_num) {
    cout << "The number of desserts is " << dessert_num << endl;
}

void output(float prep) {
    cout << "Prep time is " << prep << " minutes" << endl;
}

... 

In the example, we’ve introduced a function called output() that will return a different string depending on whether the data type is an integer or a float.

Types of Polymorphism

Polymorphism can come into play both during code compilation and also during runtime.

Compile Time Polymorphism

Compile time polymorphism takes place when a program is being compiled. C++ polymorphism occurs in this phase when either a function or an operator is overloaded. This type of polymorphism is also known as static or early binding.

Compile time polymorphism comes in two forms in C++: function overloading and operator overloading.

Function Overloading

As alluded, function overloading allows us to use the same function multiple times, with the action or output of that function dependent on its assigned data type. Here’s how function overloading works in code:

...

void output(int dessert_num) {
    cout << "The number of desserts is " << dessert_num << endl;
}

void output(float prep) {
    cout << "Prep time is " << prep << " minutes" << endl;
}

void output(string dessert) {
    cout << "The dessert is " << dessert << endl;
}

int main() {
    int x; float y; string z;
    cout << "Input a number of desserts:" << endl;
    cin >> x;
    cout << "Input a a prep time to two decimal places:" << endl;
    cin >> y;
    cout << "Input a dessert's name:" << endl;
    cin >> z;
   
    output(x);
    output(y);
    output(z);
    return 0;
}

We use the same output() function to output a different result depending on the data type of the function’s input. The program prompts the user for a series of values, and returns those values with the correct string. Using 6, 30.25, and Cookie, we get the following:

The number of desserts is 6
Prep time is 30.25 minutes
The dessert is Cookies

The program returns the correct outputs based on the inputs.

Operator Overloading

C++ allows us to add additional tasks to operators by using the operator keyword followed by the operator itself. Operators cover a wide range of uses in C++, from arithmetic to comparisons and logical statements. We can give a special meaning to an operator for a particular class without changing its original meaning for the rest of the program. We call this operator overloading.

In this example, we overload the + operator:

...

class Dessert
{
private:
int dessert_num {};

public:
Dessert(int dessert) {dessert_num = dessert;}
friend Dessert operator+(const Dessert &d1, const Dessert &d2);
int getDessert() const {return dessert_num;}
};

Dessert operator+(const Dessert &d1, const Dessert &d2)
{
return Dessert(d1.dessert_num + d2.dessert_num);
}

int main()
{
Dessert dessert1{15};
Dessert dessert2{12};
Dessert dessertSum{dessert1 + dessert2};
cout << "There are a total of " << dessertSum.getDessert() << " desserts between the two types." << endl;
return 0;
}

In this example, we were able to overload the + operator and use our Dessert class to define and add the amount of two different dessert types together. We get There are a total of 27 desserts between the two types. as our result.

Runtime Polymorphism

Runtime polymorphism in C++ uses function overriding and takes place while a program is in the run state. In this form of polymorphism, the program has to discover which definition of a function it needs to use based on the information in the main() function. Since this happens during runtime, the process is slower compared to compile time polymorphism.

Function Overriding

As introduced earlier, function overriding is a form of C++ polymorphism that centers on functions in class inheritance. To adapt our previous example, we’ll now add the main() function to help the program figure out which function definitions it needs to use:

...

class Dessert {
  public:
int prep;
void set_value (int p) {
  prep = p;
}
void ingredient() {
    cout << "Desserts have delicious ingredients.";
}
};

class Cookie: public Dessert {
  public:
void ingredient() {
  cout << "Cookies are made from flour." << endl << "Cookies take " << prep << " minutes to bake." << endl;
}
};

class IceCream: public Dessert {
  public:
void ingredient() {
  cout << "Ice cream is made from milk." << endl << "Ice cream takes " << prep << " minutes to churn." << endl;
}
};

int main() {
  Cookie c = Cookie();
  IceCream i = IceCream();
  c.set_value (30);
  i.set_value (20);
  c.ingredient();
  i.ingredient();
  return 0;
}

Each of the above classes has an ingredient() function that the program can use. In the main() function, we assign values to our child classes Cookie and IceCream, and use those designations to assign values for set_value() in each class. main() also specifies that we’re only interested in the definitions of the ingredient() function from the Cookie and IceCream classes.

Based on these parameters, we get the following output:

Cookies are made from flour.Cookies take 30 minutes to bake.Ice cream is made from milk.Ice cream takes 20 minutes to churn.

As instructed, the program ignored the ingredient() function from the Dessert parent class, and gave us the outputs we were seeking.

Learn C++ Online With Udacity

Developers who understand polymorphism are able to write streamlined code in C++. Polymorphism allows us to use inheritance, overriding, and overloading to streamline code for easy readability and faster runtimes. Furthermore, we can use the specifics of compile time and runtime polymorphism to maximize this result.

At Udacity, we offer a C++ Nanodegree program that guides you through five real-world projects to turn you into a fully fledged C++ developer.

Enroll in our C++ Nanodegree program today!

Complete Code Examples

Example 1: Using the + operator in different ways

#include <iostream>
#include <string>

using namespace std;

int main() {
    int num_desserts = 24 + 35;  // + operator used for addition
    cout << num_desserts << endl;
    string str1 = "We can combine strings ";
    string str2 = "that talk about delicious desserts";
    string str = str1 + str2; // + operator used for combining two strings
    cout << str << endl;
    return 0;
}

Example 2: Function Overloading

#include <iostream>
#include <string>
using namespace std;

void output(int dessert_num) {
    cout << "The number of desserts is " << dessert_num << endl;
}

void output(float prep) {
    cout << "Prep time is " << prep << " minutes" << endl;
}

void output(string dessert) {
    cout << "The dessert is " << dessert << endl;
}

int main() {
    int x; float y; string z;
    cout << "Input a number of desserts:" << endl;
    cin >> x;
    cout << "Input a a prep time to two decimal places:" << endl;
    cin >> y;
    cout << "Input a dessert's name:" << endl;
    cin >> z;
   
    output(x);
    output(y);
    output(z);
    return 0;
}

Example 3: Operator Overloading

Note: you might need to pass a -std=c++0x to your compiler to compile this snippet.

#include <iostream>

using namespace std;

class Dessert
{
private:
int dessert_num {};

public:
Dessert(int dessert) {dessert_num = dessert;}
friend Dessert operator+(const Dessert &d1, const Dessert &d2);
int getDessert() const {return dessert_num;}
};

Dessert operator+(const Dessert &d1, const Dessert &d2)
{
return Dessert(d1.dessert_num + d2.dessert_num);
}

int main()
{
Dessert dessert1{15};
Dessert dessert2{12};
Dessert dessertSum{dessert1 + dessert2};
cout << "There are a total of " << dessertSum.getDessert() << " desserts between the two types." << endl;
return 0;
}

Example 4: Function Overriding

#include <iostream>

using namespace std;

class Dessert {
  public:
int prep;
void set_value (int p) {
  prep = p;
}
void ingredient() {
    cout << "Desserts have delicious ingredients.";
}
};

class Cookie: public Dessert {
  public:
void ingredient() {
  cout << "Cookies are made from flour." << endl << "Cookies take " << prep << " minutes to bake." << endl;
}
};

class IceCream: public Dessert {
  public:
void ingredient() {
  cout << "Ice cream is made from milk." << endl << "Ice cream takes " << prep << " minutes to churn." << endl;
}
};

int main() {
  Cookie c = Cookie();
  IceCream i = IceCream();
  c.set_value (30);
  i.set_value (20);
  c.ingredient();
  i.ingredient();
  return 0;
}