Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

ポリモーフィズム(多態性)の4つの種類|アドホック・包含・パラメトリック・型強制をC++コード例で解説

ポリモーフィズム(多態性)とは、同じインターフェースでありながら、扱う型に応じて異なる動作を実現できるオブジェクト指向プログラミングの重要な概念です。ポリモーフィズムには主に以下の4つの種類があります。

  • アドホック多相(Ad-Hoc Polymorphism)
  • 包含多相(Inclusion Polymorphism)
  • パラメトリック多相(Parametric Polymorphism)
  • 型強制多相(Coercion Polymorphism)

1. アドホック多相(オーバーロード)

アドホック多相は「オーバーロード(多重定義)」とも呼ばれます。同じ名前の関数が、引数の型に応じて異なる動作を行えるようにする仕組みです。関数と演算子のどちらもオーバーロードできますが、言語によっては演算子オーバーロードをサポートしていない場合もあります。一方、関数オーバーロードは多くの言語で広くサポートされている一般的な機能です。

サンプルコード

#include <iostream>
using namespace std;

int add(int a, int b) {
    return a + b;
}

string add(string a, string b) {
    return a + b;  // 文字列の連結
}

int main() {
    cout << "数値の加算: " << add(2, 7) << endl;
    cout << "文字列の結合: " << add("hello", "World") << endl;
}

実行結果

数値の加算: 9
文字列の結合: helloWorld

この例では、同じ add という関数名でも、int型を渡せば数値の加算が、string型を渡せば文字列の連結が行われます。これがアドホック多相の基本的な動作です。

2. 包含多相(サブタイピング)

包含多相は「サブタイピング」とも呼ばれます。基底クラスのポインタや参照を使って、派生クラスのオブジェクトを操作できるようにするもので、実行時ポリモーフィズム(動的バインディング)に分類されます。実際のオブジェクトの型が確定するのはプログラムの実行時であるため、C++でこの多相性を実現するには仮想関数(virtual 関数)が必要です。

サンプルコード

#include <iostream>
using namespace std;

class Base {
    public:
        virtual void print() {
            cout << "これは基底クラスです。" << endl;
        }
};

class Derived : public Base {
    public:
        void print() {
            cout << "これは派生クラスです。" << endl;
        }
};

int main() {
    Base *ob1;
    Base base_obj;
    Derived derived_obj;

    ob1 = &base_obj;      // 基底クラスのオブジェクトを指す
    ob1->print();

    ob1 = &derived_obj;   // 同じポインタで派生クラスのオブジェクトを指す
    ob1->print();
}

実行結果

これは基底クラスです。
これは派生クラスです。

同じ基底クラス型のポインタ ob1 でありながら、指し示すオブジェクトに応じて呼び出される関数が切り替わっています。これが仮想関数による動的な多相性です。

3. 型強制多相(キャスト)

型強制多相は「キャスティング(型変換)」とも呼ばれます。あるオブジェクトやプリミティブ型の値が、別の型へ変換されるときに発生する多相性です。キャストには2種類あります。暗黙的キャストはコンパイラが自動的に行うもので、明示的キャストは const_castdynamic_cast などを用いてプログラマが意図的に行うものです。

サンプルコード

#include <iostream>
using namespace std;

class Integer {
    int val;
    public:
        Integer(int x) : val(x) {
        }
        operator int() const {  // int型への暗黙的変換
            return val;
        }
};

void display(int x) {
    cout << "値は: " << x << endl;
}

int main() {
    Integer x = 50;
    display(100);
    display(x);  // Integer型が自動的にint型へ変換される
}

実行結果

値は: 100
値は: 50

変換演算子 operator int() を定義することで、Integer型のオブジェクトがint型が必要な場面で自動的に整数へ変換され、意図どおりの動作を実現できています。

4. パラメトリック多相(テンプレート)

パラメトリック多相は、まったく同じコードを異なる型に対して再利用できるようにする多相性です。C++ではテンプレートを使用することで実現でき、型はコンパイル時に決定されるため、早期バインディング(静的バインディング)として扱われます。

サンプルコード

#include <iostream>
using namespace std;

template <class T>
T maximum(T a, T b) {
    if(a > b) {
        return a;
    } else {
        return b;
    }
}

int main() {
    cout << "maximum(156, 78): " << maximum(156, 78) << endl;
    cout << "maximum('A', 'X'): " << maximum('A', 'X') << endl;
}

実行結果

maximum(156, 78): 156
maximum('A', 'X'): X

テンプレート関数 maximum は一度だけ定義していますが、int型でもchar型でも同じロジックが正しく動作します。このように型に依存しない汎用的なコードを書けるのがパラメトリック多相の大きな利点です。

まとめ

ポリモーフィズムは、アドホック多相(オーバーロード)、包含多相(サブタイピングと仮想関数)、型強制多相(キャスト)、パラメトリック多相(テンプレート)の4種類に分類できます。それぞれ実現方法と動作のタイミング(コンパイル時か実行時か)が異なるため、用途に応じて適切に使い分けることで、柔軟で再利用性の高いコードを書くことができます。

  1. C言語の基本データ型を徹底解説!int・char・floatの種類とサイズ一覧

    C言語の基本データ型とは? C言語のコンパイラがサポートする基本データ型は、大きく分けて次の4つです。 整数型(Integer) 文字型(Character) 浮動小数点型(Floating-point) 倍精度浮動小数点型(Double precision floating point) プログラムで扱う値の種類(整数・文字・実数など)に応じて適切な型を選ぶことは、正確で効率的なコードを書くための第一歩です。なお、各データ型のサイズや表現できる値の範囲は、使用するコンパイラや実行環境によって異なる場合がある点に注意してください。 整数型(Integral Data Type) 整数型は

  2. C/C++における引数の型強制(Argument Coercion)とは?仕組みとサンプルコードで解説

    本記事では、C言語およびC++における「引数の型強制(Argument Coercion)」について解説します。引数の型強制とは、関数に渡された引数の型を、コンパイラがある型から別の型へ自動的に(暗黙的に)変換する仕組みのことです。この変換は「引数の昇格ルール(argument promotion rule)」に従って行われます。つまり、より小さいデータ型の引数は、より大きいデータ型へと変換されますが、その逆の変換は行われません。なぜなら、大きなデータ型から小さなデータ型へ変換すると、データの一部が失われる(桁あふれや精度の低下が発生する)恐れがあるためです。暗黙的な型変換がどのように行われる