This problem was asked by Microsoft.

Describe and give an example of each of the following types of polymorphism:

  • Ad-hoc polymorphism
  • Parametric polymorphism
  • Subtype polymorphism

My Solution(C++):


/*
types of polymorphism:
1 - ad-hoc; or overloading further subdivided into function overloading and operator overloading.
eg. func(int), func(int, int): same function with 2/more signatures. only by arguments (#args, type of args) not by return type.
2 - parametric; meaning function which can accept any type of argument eg
template<typename T>
func(T t);
This is also called compile time polymorphism
3 - Subtype polymorphism (this is what they mean when they say polymorphism); this is achieved by function overriding ie overriding a function of base class in the child class. Most often, we override a virtual function if the base class is abstract.
Mental note - You cannot have objects of abstract classes(however you can have pointers), hence making this polymorphism extremely useful for such classes.
This is also caled Run-time polymorphism.
4 - coercion polymorphism or casting; is of two types - implicit eg when a func(int x) is called on a double, the compiler accepts it by casting the variable to int, and explicit ie using static_cast, dynamic_cast, interpret_cast.
subtype polymorphism can be seen as a special case of coercion polymorphism.
*/

#include <iostream>
#include <vector>
#include <string>

// ad-hoc polymorphism
int add(int a, int b){
  std::cout<<"add method with 2 args"<<'\n';
  return a+b;
}

int add(int a, int b, int c){
  std::cout<<"add method with 3 args"<<'\n';
  return a+b+c;
}

void test1(){
  add(1, 2);
  add(1, 2, 3);
}


// parametric polymorphism
template<typename T>
T combine(const std::vector<T> &v, T init_val){
  T sum = init_val;
  for (int i=0; i<v.size(); i++){
    sum+=v[i];
  }
  return sum;
}

#define str std::string
void test2(){
  std::cout<<combine({1, 2}, 0)<<'\n';
  std::cout<<combine({str("hello "), str("world")}, str(""))<<'\n';
}


//Subtype polymorphism
class Base_{
public:
  virtual void show() = 0;
};
//example of an abstract class
//above class can't be used to create an object. We must override the show method.

class Child_: public Base_{
public:
  void show(){
    std::cout<<"show method in child"<<'\n';
  }
};
//usable class

void test3(){
  Child_ c;
  c.show();
}


//coercion polymorphism
class crazyInt{
private:
  int val;
public:
  crazyInt(int i){
    val = i;
  }
  operator int() const{
    return val;
  } //this will enable an object of type crazyint to be used as an int
};

void test4(){
  crazyInt c = 25; //possible because of the operator int method
  std::cout<<"tests successful"<<'\n';
}


int main(){
  std::cout<<"--Ad-hoc polymorphism--"<<'\n';
  test1();
  std::cout<<"--Parametric polymorphism--"<<'\n';
  test2();
  std::cout<<"--Subtype polymorphism--"<<'\n';
  test3();
  std::cout<<"--Coercion polymorphism--"<<'\n';
  test4();
  return 0;
}