Menu
Coddy logo textTech

コンパイル時 vs 実行時ポリモーフィズム

CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 25/70。

ポリモーフィズム(多態性)とは「多くの形態」を意味し、同じコードが文脈に応じて異なる動作をする能力のことです。C#は2つの異なる種類のポリモーフィズムをサポートしており、それぞれがいつ解決されるかを理解することは、より柔軟なコードを書くのに役立ちます。

コンパイル時ポリモーフィズム(静的ポリモーフィズムとも呼ばれます)は、プログラムが実行される前にコンパイラによって解決されます。メソッドのオーバーロードがその主な例です。複数のメソッドが同じ名前を共有しますが、異なるパラメータを持っています:

public class Calculator
{
    public int Add(int a, int b) => a + b;
    public double Add(double a, double b) => a + b;
}

var calc = new Calculator();
calc.Add(5, 3);       // Compiler picks int version
calc.Add(5.0, 3.0);   // Compiler picks double version

コンパイラは引数の型を検証し、コンパイル時に適切なメソッドを選択します。この決定は、プログラムが実行される前に確定します。

実行時ポリモーフィズム (動的ポリモーフィズム) は、プログラムの実行中に解決されます。これは virtual メソッドと override メソッドで発生します。オブジェクトの実際の型によって、どのメソッドが実行されるかが決まります。

Animal pet = new Dog();  // Animalとして宣言されているが、実際にはDog
pet.Speak();             // 実行時にDogのSpeak()を呼び出す

コンパイラは、どの Speak() が実行されるかを知りません。その決定は、オブジェクトの実際の型に基づいて実行時に行われます。これこそが、柔軟で拡張可能なシステムを構築する上で、継承ベースのポリモーフィズムを非常に強力なものにしている理由です。

challenge icon

チャレンジ

簡単

2つのタイプのポリモーフィズムを実際に動作させるコンバーターシステムを構築しましょう。メソッドのオーバーロード(コンパイル時ポリモーフィズム)を使用するクラスと、仮想/オーバーライドメソッド(実行時ポリモーフィズム)を使用する継承階層を作成します。

コードは4つのファイルに分けて構成します:

  • Converter.cs: Conversion 名前空間内に Converter クラスを定義します。このクラスは、メソッドのオーバーロードを通じてコンパイル時ポリモーフィズムを示します。3つのオーバーロードされた Convert メソッドを作成してください:
    • Convert(int value)"Integer: {value}" を返します
    • Convert(double value)"Double: {value}" を返します
    • Convert(string value)"String: {value}" を返します
  • Shape.cs: Conversion 名前空間内にベースとなる Shape クラスを定義します。このクラスには Name プロパティ(string)と、それを設定するコンストラクタがあります。"This is a {Name}" を返す virtual メソッド Describe() を含めてください。
  • Circle.cs: Conversion 名前空間内に Shape を継承する Circle クラスを定義します。Radius プロパティ(double)を追加します。コンストラクタは半径を受け取り、ベースコンストラクタに "Circle" を渡します。Describe() をオーバーライドして、"This is a Circle with radius {Radius}" を返すようにします。
  • Program.cs: メインファイルで、両方のタイプのポリモーフィズムを実演します。まず、Converter を作成し、入力値を使用して3つのオーバーロードされたメソッドすべてを呼び出します。次に Circle を作成して Shape 型の変数に格納し、Describe() を呼び出して実行時ポリモーフィズムを示します。

4つの入力を受け取ります:

  • 整数値
  • double値
  • 文字列値
  • 円の半径(double)

出力を以下の形式で表示してください:

Compile-time Polymorphism:
{Convert(int) result}
{Convert(double) result}
{Convert(string) result}
Runtime Polymorphism:
{Describe() result from Shape variable holding Circle}

例えば、入力が 423.14Hello5.5 の場合、出力は以下のようになります:

Compile-time Polymorphism:
Integer: 42
Double: 3.14
String: Hello
Runtime Polymorphism:
This is a Circle with radius 5.5

重要な違いに注目してください。コンパイラはコンパイル時に引数の型に基づいてどの Convert メソッドを呼び出すかを決定しますが、Describe() メソッドは、たとえ Shape 型の変数に格納されていても、実行時に実際のオブジェクトの型に基づいて解決されます!

チートシート

ポリモーフィズム(多態性)とは「多くの形態」を意味し、同じコードがコンテキストに応じて異なる動作をする能力のことです。

コンパイル時ポリモーフィズム(静的ポリモーフィズム)は、プログラムが実行される前にコンパイラによって解決されます。メソッドのオーバーロードがその主な例です:

public class Calculator
{
    public int Add(int a, int b) => a + b;
    public double Add(double a, double b) => a + b;
}

var calc = new Calculator();
calc.Add(5, 3);       // Compiler picks int version
calc.Add(5.0, 3.0);   // Compiler picks double version

コンパイラは引数の型を調べ、コンパイル時に正しいメソッドを選択します。

実行時ポリモーフィズム(動的ポリモーフィズム)は、プログラムの実行中に virtual および override メソッドを使用して解決されます:

Animal pet = new Dog();  // Declared as Animal, actually a Dog
pet.Speak();             // Calls Dog's Speak() at runtime

宣言された変数の型ではなく、オブジェクトの実際の型によって、実行時にどのメソッドが実行されるかが決定されます。

自分で試してみよう

using System;
using Conversion;

class Program
{
    public static void Main(string[] args)
    {
        // 入力を読み込む
        int intValue = Convert.ToInt32(Console.ReadLine());
        double doubleValue = Convert.ToDouble(Console.ReadLine());
        string stringValue = Console.ReadLine();
        double radius = Convert.ToDouble(Console.ReadLine());

        // TODO: コンパイル時ポリモーフィズムを実演する
        // Converter オブジェクトを作成し、オーバーロードされた 3 つの Convert メソッドをすべて呼び出す
        Console.WriteLine("Compile-time Polymorphism:");
        // intValue、doubleValue、および stringValue を使用して Convert を呼び出す

        // TODO: 実行時ポリモーフィズムを実演する
        // Circle オブジェクトを作成し、それを Shape 変数に格納する
        // 次に、Shape 変数に対して Describe() を呼び出す
        Console.WriteLine("Runtime Polymorphism:");
        // Circle を作成し、Describe() を呼び出す
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン