はじめに
ポリモーフィズム自体は何度か聞いたことがあったけど,なんとなくの理解で流していたので,自分の備忘録かつしっかりと言語化することで理解しようということで,簡単にまとめてみました.
ポリモーフィズムとは?
Wikipediaで調べてみると...
ポリモーフィズム(英: Polymorphism)とは、プログラミング言語の型システムの性質を表すもので、プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。ポリモルフィズム、多態性、多相性、多様性とも呼ばれる。対義語はモノモーフィズム (Monomorphism)、単態性、単相性で、プログラミング言語の各要素が唯一つの型に属するという性質を指す。
簡単に説明すると,
ある関数(orメソッド)が同じ名前なのに引数・返り値(の型)が異なるとき,その関数を「ポリモーフィズムな関数」や「多相的関数」という感じでしょうか.
例えば,C++では
#include <iostream>
void print(int i)
{
std::cout << "Int: "<< i << std::endl;
}
void print(double f)
{
std::cout << "Float: " << f << std::endl;
}
int main()
{
print(10); // >> Int: 10
print(10.0); // >> Float: 10.0
}
のように同じprint
という名前の関数が引数の型(int or double)によって異なる挙動を示すような場合です.
ポリモーフィズムの分類
ポリモーフィズムはいくつかの種類に分類できます.
-
アドホック多相; Ad hoc polymorphism
- ある関数が,異なる型の引数に対してそれぞれ異なる実装を持つ場合.
- いわゆる*「多重定義」*(C++でいう「オーバーロード」)
-
パラメータ多相; Parameteric polymorphism
- コードが特定の方を指定せずに書かれる事でさまさまな型に対して透過的に使用できる場合
- C++の「テンプレート template」
- Javaの「ジェネリクス generics」
-
サブタイピング多相; Subtyping polymorphism (部分型付け; Subtyping)
- 共通の上位型を持つ複数の型を,1つの名前で扱う場合
- オブジェクト指向言語で,親クラスから派生(継承)した子クラスがメソッドの内容を上書き(オーバーライド)する場合
先程示した例は,**「アドホック多相な関数」**の例ということになります.
ポリモーフィズムの実装
先程示したそれぞれの種類についてざっくりとですが,C++で実装してみます.
- アドホック多相
これは先程も実装しましたが,オーバーロードですね
#include <iostream>
#include <string>
int add(int x, int y)
{
return x + y;
}
std::string add(const std::string& s1, const std::string& s2)
{
return s1 + s2;
}
int main()
{
std::cout << add(1, 2) << std::endl; // >> 3
std::cout << add("Hello, ", "World") << std::endl; // >> Hello, World
}
- パラメータ多相
テンプレートで任意の型を許容できるようにする!(雑)
#include <iostream>
template<typename T>
void print(T t)
{
std::cout << t << std::endl;
}
int main()
{
print(10); // >> 10
print(10.0); // >> 10.0
print("ten"); // >> ten
}
- サブタイピング多相
「継承」して「オーバーライド」って感じですね
#include <iostream>
#include <string>
// Parent
class Person
{
public:
std::string name;
int age;
Person(std::string name, int age);
virtual void say_hello();
};
Person::Person(std::string name, int age)
{
this->name = name;
this->age = age;
}
void Person::say_hello()
{
std::cout << "Hello! My name is " << this->name << ", " << this->age << " years old." << std::endl;
}
// Child
class Japanese : public Person
{
public:
Japanese(std::string name, int age);
virtual void say_hello();
};
Japanese::Japanese(std::string name, int age) : Person(name, age){};
void Japanese::say_hello()
{
std::cout << "こんにちは!私の名前は " << this->name << ", " << this->age << " 歳です." << std::endl;
}
int main()
{
Person p("John", 29);
Japanese j("太郎", 24);
p.say_hello();
j.say_hello();
return 0;
}
後半少し雑になってしまいましたが,実際に実装を見てみることでポリモーフィズムの理解には繋がったと思います.
今後もう少し深堀できていけたらなと思います.