Open In App

Ad-hoc, Inclusion, Parametric & Coercion Polymorphisms

Improve
Improve
Like Article
Like
Save
Share
Report

When we talk about Polymorphism in C++, we come to hear the following four types: Discussing these in details:

  1. Ad-hoc Polymorphism, also called as Overloading Ad-hoc Polymorphism allows functions having same name to act differently for different types. For example: The + operator adds two integers and concatenates two strings. Above example could be better illustrated by invoking the function “sum()” in under-mentioned code: 

CPP14




#include <iostream>
using namespace std;
 
int sum(int x, int y)
{
    int c = x + y;
    return c;
}
 
string sum(const char* x, const char* y)
{
    string summation(x);
    summation += y;
    return summation;
}
 
int main()
{
    cout << sum(50, 20)
        << " :- Integer addition Output\n";
    cout << sum("Polymorphism", " achieved")
        << " :- String Concatenation Output\n";
}


Java




import java.util.*;
 
public class Main {
    public static int sum(int x, int y)
    {
        int c = x + y;
        return c;
    }
 
    public static String sum(String x, String y)
    {
        String summation = x.concat(y);
        return summation;
    }
 
    public static void main(String[] args)
    {
        System.out.println(sum(50, 20)
                           + " :- Integer addition Output");
        System.out.println(
            sum("Polymorphism", " achieved")
            + " :- String Concatenation Output");
    }
}


Python3




def sum(x, y):
    c = x + y
    return c
 
def sum_str(x, y):
    summation = x + y
    return summation
 
# Main function
if __name__ == '__main__':
    print(f"{sum(50, 20)} :- Integer addition Output")
    print(f"{sum_str('Polymorphism', ' achieved')} :- String Concatenation Output")


C#




using System;
 
class Program
{
    static int Sum(int x, int y)
    {
        int c = x + y;
        return c;
    }
 
    static string SumStr(string x, string y)
    {
        string summation = x + y;
        return summation;
    }
    // Main function
    static void Main(string[] args)
    {
        Console.WriteLine($"{Sum(50, 20)} :- Integer addition Output");
        Console.WriteLine($"{SumStr("Polymorphism", " achieved")} :- String Concatenation Output");
    }
}


Javascript




// JavaScript program to perform addition of integers and concatenation of strings
 
function sum(x, y) {
  let c = x + y;
  return c;
}
 
function sumStr(x, y) {
  let summation = x + y;
  return summation;
}
 
// Main function
if (require.main === module) {
  console.log(`${sum(50, 20)} :- Integer addition Output`);
  console.log(`${sumStr('Polymorphism', ' achieved')} :- String Concatenation Output`);
}


Output

70 :- Integer addition Output
Polymorphism achieved :- String Concatenation Output





  1. Hence, by calling two different functions(which differ in the type of arguments) having the same names, to execute multiple operations, we have successfully achieved Ad-hoc Polymorphism.
  2. Inclusion Polymorphism, also called as Subtyping Inclusion Polymorphism is the ability to use derived classes through base class pointers and references. It is also known as Run-time polymorphism because the address of the function is not located by the Compiler at compile-time, rather, the right pointer from the virtual table is dereferenced to invoke the function at run-time. The concept of Virtual Function, also known as Dynamic Linkage, is employed to achieve Inclusion Polymorphism. The usage of Virtual Function allows the selection of that function which is to be invoked based on the kind of object for which it is called. For example: To implement such a Polymorphism technique, let us take different files under consideration such as .jpg, .gif, .png files. All these files fall under the category of Image Files. So, they can be represented as Classes Derived from Image Base Class and overriding the display() pure virtual function. Above example could be better understood by the following illustration: 

CPP14




#include <iostream>
using namespace std;
 
class Image {
 
public:
    Image()
    {
    }
 
    virtual void display() = 0;
};
class Jpg : public Image {
public:
    Jpg()
    {
    }
 
    void display()
    {
        cout << "JPG Image File" << endl;
    }
};
 
class Png : public Image {
public:
    Png()
    {
    }
 
    void display()
    {
        cout << "PNG Image File" << endl;
    }
};
 
// Main function
int main()
{
    Image* img;
    Jpg jg;
    Png pg;
 
    // stores the address of Jpg
    img = &jg;
 
    // invoking display() func of Jpg
    img->display();
 
    // stores the address of Png
    img = &pg;
 
    // invoking display() func of Png
    img->display();
 
    return 0;
}


Java




abstract class Image {
    public Image() {
    }
 
    abstract void display();
}
 
class Jpg extends Image {
    public Jpg() {
    }
 
    @Override
    void display() {
        System.out.println("JPG Image File");
    }
}
 
class Png extends Image {
    public Png() {
    }
 
    @Override
    void display() {
        System.out.println("PNG Image File");
    }
}
 
public class Main {
    public static void main(String[] args) {
        Image img;
        Jpg jg = new Jpg();
        Png pg = new Png();
 
        // stores the reference of Jpg
        img = jg;
 
        // invoking display() method of Jpg
        img.display();
 
        // stores the reference of Png
        img = pg;
 
        // invoking display() method of Png
        img.display();
    }
}


Python3




from abc import ABC, abstractmethod
 
class Image(ABC):
    def __init__(self):
        pass
 
    @abstractmethod
    def display(self):
        pass
 
class Jpg(Image):
    def __init__(self):
        pass
 
    def display(self):
        print("JPG Image File")
 
class Png(Image):
    def __init__(self):
        pass
 
    def display(self):
        print("PNG Image File")
 
# Main function
def main():
    img = None
    jg = Jpg()
    pg = Png()
 
    # stores the instance of Jpg
    img = jg
 
    # invoking display() method of Jpg
    img.display()
 
    # stores the instance of Png
    img = pg
 
    # invoking display() method of Png
    img.display()
 
if __name__ == "__main__":
    main()


C#




using System;
 
abstract class Image
{
    public Image()
    {
    }
 
    public abstract void Display();
}
 
class Jpg : Image
{
    public Jpg()
    {
    }
 
    public override void Display()
    {
        Console.WriteLine("JPG Image File");
    }
}
 
class Png : Image
{
    public Png()
    {
    }
 
    public override void Display()
    {
        Console.WriteLine("PNG Image File");
    }
}
 
class MainClass
{
    public static void Main(string[] args)
    {
        Image img;
        Jpg jg = new Jpg();
        Png pg = new Png();
 
        // stores the reference of Jpg
        img = jg;
 
        // invoking display() method of Jpg
        img.Display();
 
        // stores the reference of Png
        img = pg;
 
        // invoking display() method of Png
        img.Display();
    }
}


Javascript




// Define an abstract class Image using ES6 class syntax
class Image {
    constructor() {
        // Constructor for the abstract class
    }
 
    // Define an abstract method display using ES6 class syntax
    display() {
        // Abstract method to be implemented by subclasses
    }
}
 
// Subclass Jpg extending from the abstract class Image
class Jpg extends Image {
    constructor() {
        super(); // Call the constructor of the superclass
    }
 
    display() {
        console.log("JPG Image File");
    }
}
 
// Subclass Png extending from the abstract class Image
class Png extends Image {
    constructor() {
        super(); // Call the constructor of the superclass
    }
 
    display() {
        console.log("PNG Image File");
    }
}
 
// Main function
function main() {
    let img = null;
    const jg = new Jpg(); // Create an instance of Jpg
    const pg = new Png(); // Create an instance of Png
 
    // Store the instance of Jpg
    img = jg;
 
    // Invoke the display() method of Jpg
    img.display();
 
    // Store the instance of Png
    img = pg;
 
    // Invoke the display() method of Png
    img.display();
}
 
// Check if the script is the main module
if (require.main === module) {
    main(); // Call the main function if this script is executed directly
}


Output

JPG Image File
PNG Image File





  1. Hence, in the above code, we have two different Classes with a function having the same name and not differing by Parameters, but with different implementations.
  2. Coercion Polymorphism, also called as Casting Coersion Polymorphism occurs when an object or primitive is cast into some other type. It could be either Implicit or Explicit. Implicit casting happens as a responsibility of Compiler itself. For example: float f=100 (integer implicitly gets promoted to float) Explicit casting makes use of some type-casting expressions such as const_cast, dynamic_cast, etc. For example: When a class defines conversion operator for some type, say “int”, then, it could be employed anywhere in the program where integer type data is expected. Illustration Below could make it more easier to understand: This above illustration could be more clarified with help of code below: 

CPP14




#include <iostream>
using namespace std;
 
class IntClass {
    int num;
 
public:
    IntClass(int a)
        : num(a)
    {
    }
 
    operator int() const
    {
        return num;
    } // conversion from User-defined type to Basic type
};
 
void show(int x)
{
    cout << x << endl;
}
 
int main()
{
    IntClass i = 100;
    show(746); // outputs 746
    show(i); // outputs 100
}


Java




class IntClass {
    private int num;
 
    public IntClass(int a) {
        num = a;
    }
 
    public int intValue() {
        return num;
    } // conversion from User-defined type to Basic type
}
 
class Main {
    public static void show(int x) {
        System.out.println(x);
    }
 
    public static void main(String[] args) {
        IntClass i = new IntClass(100);
        show(746);
        show(i.intValue());
    }
}


Python3




# Python Program for the above approach
 
class IntClass:
    def __init__(self, a):
        self.num = a
 
    def intValue(self):
        return self.num
    # conversion from User-defined type to Basic type
 
def show(x):
    print(x)
 
i = IntClass(100)
show(746)
show(i.intValue())
 
# This code is contributed by princekumaras


C#




// C# program for the above approach
 
using System;
 
class IntClass {
    private int num;
 
    public IntClass(int a) {
        num = a;
    }
 
    public static implicit operator int(IntClass i) {
        return i.num;
    } // conversion from User-defined type to Basic type
}
 
class MainClass {
    public static void show(int x) {
        Console.WriteLine(x);
    }
 
    public static void Main(string[] args) {
        IntClass i = new IntClass(100);
        show(746);
        show(i);
    }
}
 
// This code is contributed by princekumras


Javascript




// JavaScript program for the above approach
 
class IntClass {
    constructor(a) {
        this.num = a;
    }
 
    intValue() {
        return this.num;
    } // conversion from User-defined type to Basic type
}
 
function show(x) {
    console.log(x);
}
 
let i = new IntClass(100);
show(746);
show(i.intValue());
 
// This code is contributed by princekumaras


Output

746
100





  1. The IntClass reference is used in place of integer type argument, and hence, the concept of Casting is well understood.
  2. Parametric Polymorphism, also called as Early Binding Parametric Polymorphism opens a way to use the same piece of code for different types. It is implemented by the use of Templates. For example: To develop an understanding of this sort of polymorphism, let us execute a program for finding greater of two Integers or two Strings, 

CPP14




#include <iostream>
#include <string>
using namespace std;
 
template <class temp>
temp greater(temp a, temp b)
{
    if (a > b)
        return a;
    else
        return b;
}
 
int main()
{
    cout << ::greater(55, 11) << endl;
 
    string str1("Early"), str2("Binding");
    cout << ::greater(str1, str2) << endl;
}


Java




public class GreaterDemo {
    // Generic method to find the greater of two values
    public static <T extends Comparable<T>> T greater(T a, T b) {
        if (a.compareTo(b) > 0) {
            return a;
        } else {
            return b;
        }
    }
 
    public static void main(String[] args) {
        // Example with integers
        System.out.println(greater(55, 11));
 
        // Example with strings
        String str1 = "Early";
        String str2 = "Binding";
        System.out.println(greater(str1, str2));
    }
}


Python




def greater(a, b):
    """
    Function to return the greater of two values.
 
    Parameters:
    - a: First value
    - b: Second value
 
    Returns:
    - The greater of the two values
    """
    if a > b:  # Check if a is greater than b
        return # Return a if it's greater
    else:
        return # Otherwise, return b
 
 
if __name__ == "__main__":
    # Test with integer values
    print(greater(55, 11))
 
    # Test with string values
    str1 = "Early"
    str2 = "Binding"
    print(greater(str1, str2))


C#




using System;
 
public class GreaterDemo {
    // Generic method to find the greater of two values
    public static T Greater<T>(T a, T b) where T : IComparable<T> {
        if (a.CompareTo(b) > 0) {
            return a;
        } else {
            return b;
        }
    }
 
    public static void Main(string[] args) {
        // Example with integers
        Console.WriteLine(Greater(55, 11));
 
        // Example with strings
        string str1 = "Early";
        string str2 = "Binding";
        Console.WriteLine(Greater(str1, str2));
    }
}


Javascript




// Define a generic function 'greater' that compares two values and returns the greater one
function greater(a, b) {
    if (a > b) { // If 'a' is greater than 'b'
        return a; // Return 'a'
    } else { // Otherwise
        return b; // Return 'b'
    }
}
 
// Test the 'greater' function with integer values
console.log(greater(55, 11)); 
 
// Test the 'greater' function with string values
let str1 = "Early";
let str2 = "Binding"
console.log(greater(str1, str2));


Output

55
Early





  1. Using Templates, the same function can be parameterized with different types of data, but this needs to be decided at compile-time itself, and hence, this polymorphism is named so. If we wish to achieve such polymorphism for pointers, it turns into Ad-hoc Polymorphism.


Last Updated : 28 Feb, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads