工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> C言語

C#のポリモーフィズム:静的バインディングと動的バインディングを徹底解説

ポリモーフィズム(多態性)とは「多くの形を持つ」という意味です。オブジェクト指向プログラミングパラダイムでは、「1つのインターフェース、複数の機能」として表現されることが多いです。

ポリモーフィズムは静的または動的に分類されます。静的ポリモーフィズムでは、関数への応答がコンパイル時に決定されます。動的ポリモーフィズムでは、実行時に決定されます。

静的ポリモーフィズム(コンパイル時多態性)

コンパイル時に関数とオブジェクトをリンクするメカニズムを早期バインディングまたは静的バインディングと呼びます。C#では静的ポリモーフィズムを実装する2つの技術があります。

演算子オーバーロードについては次章で説明します。

関数のオーバーロード

同じスコープ内で同じ関数名の複数の定義を持てます。定義は引数リストの型と/または数で異なっていなければなりません。戻り値の型のみが異なる関数宣言をオーバーロードすることはできません。

オーバーロードの例

using System;
namespace PolymorphismApplication {
    class PrintData {
        public void Print(int i) {
            Console.WriteLine("Printing int: {0}", i);
        }
        
        public void Print(double f) {
            Console.WriteLine("Printing float: {0}", f);
        }
        
        public void Print(string s) {
            Console.WriteLine("Printing string: {0}", s);
        }
        
        static void Main(string[] args) {
            PrintData p = new PrintData();
            p.Print(5);           // int版が呼ばれる
            p.Print(500.263);     // double版が呼ばれる
            p.Print("Hello C#");  // string版が呼ばれる
            Console.ReadKey();
        }
    }
}

実行結果:

Printing int: 5
Printing float: 500.263
Printing string: Hello C#

動的ポリモーフィズム(実行時多態性)

C#では、インターフェースの部分的なクラス実装を提供するために使用される抽象クラスを作成できます。実装は派生クラスが継承するときに完了します。抽象クラスには抽象メソッドが含まれ、これは派生クラスで実装されます。派生クラスはより特化した機能を持ちます。

抽象クラスのルール

抽象クラスの例

using System;
namespace PolymorphismApplication {
    abstract class Shape {
        public abstract int Area();  // 抽象メソッド(実装なし)
    }
    
    class Rectangle : Shape {
        private int length;
        private int width;
        
        public Rectangle(int a = 0, int b = 0) {
            length = a;
            width = b;
        }
        
        public override int Area() {  // 必ずoverrideが必要
            Console.WriteLine("Rectangle class area :");
            return (width * length);
        }
    }
    
    class RectangleTester {
        static void Main(string[] args) {
            Rectangle r = new Rectangle(10, 7);
            double a = r.Area();
            Console.WriteLine("Area: {0}", a);
            Console.ReadKey();
        }
    }
}

実行結果:

Rectangle class area :
Area: 70

仮想関数(Virtual Functions)

クラスに定義された関数を派生クラスで実装させたい場合、virtual関数を使用します。仮想関数は異なる派生クラスで異なる実装を持て、これらの関数の呼び出しは実行時に決定されます。

動的ポリモーフィズムは抽象クラスと仮想関数によって実装されます。

仮想関数の例

using System;
namespace PolymorphismApplication {
    class Shape {
        protected int width, height;
        
        public Shape(int a = 0, int b = 0) {
            width = a;
            height = b;
        }
        
        // 仮想メソッド(基底実装あり)
        public virtual int Area() {
            Console.WriteLine("Parent class area :");
            return 0;
        }
    }
    
    class Rectangle : Shape {
        public Rectangle(int a = 0, int b = 0) : base(a, b) { }
        
        public override int Area() {
            Console.WriteLine("Rectangle class area :");
            return (width * height);
        }
    }
    
    class Triangle : Shape {
        public Triangle(int a = 0, int b = 0) : base(a, b) { }
        
        public override int Area() {
            Console.WriteLine("Triangle class area :");
            return (width * height / 2);
        }
    }
    
    class Caller {
        public void CallArea(Shape sh) {
            int a = sh.Area();  // 実行時に適切なメソッドが呼ばれる
            Console.WriteLine("Area: {0}", a);
        }
    }
    
    class Tester {
        static void Main(string[] args) {
            Caller c = new Caller();
            Rectangle r = new Rectangle(10, 7);
            Triangle t = new Triangle(10, 5);
            
            c.CallArea(r);  // Rectangle.Area() が呼ばれる
            c.CallArea(t);  // Triangle.Area() が呼ばれる
            Console.ReadKey();
        }
    }
}

実行結果:

Rectangle class area :
Area: 70
Triangle class area :
Area: 25

静的 vs 動的ポリモーフィズムの比較

特徴静的(オーバーロード)動的(仮想/抽象)
決定タイミングコンパイル時実行時
別名早期バインディング遅延バインディング
実現方法メソッドオーバーロード、演算子オーバーロード仮想メソッド、抽象メソッド、インターフェース
パフォーマンス高速(直接呼び出し)わずかなオーバーヘッド(vtable検索)
柔軟性コンパイル時に既知の型のみ実行時に型決定、プラグイン等に対応可能

インターフェースによるポリモーフィズム

インターフェースも動的ポリモーフィズムを実現する手段です。

interface IShape {
    double Area();
}

class Circle : IShape {
    public double Radius { get; set; }
    public double Area() => Math.PI * Radius * Radius;
}

class Square : IShape {
    public double Side { get; set; }
    public double Area() => Side * Side;
}

// 使用
IShape[] shapes = { new Circle { Radius = 5 }, new Square { Side = 4 } };
foreach (var shape in shapes) {
    Console.WriteLine($"Area: {shape.Area():F2}");
}

パターンマッチングによる型ベースの分岐(C# 7.0以降)

public static double CalculateArea(object shape) {
    return shape switch {
        Circle c => Math.PI * c.Radius * c.Radius,
        Rectangle r => r.Width * r.Height,
        Triangle t => t.Base * t.Height / 2,
        _ => throw new ArgumentException("Unknown shape")
    };
}

ベストプラクティス

C言語

  1. C# クラスとオブジェクト:堅牢な OOP の基礎
  2. C# アクセス修飾子を理解する:public、private、protected、internal など
  3. C# static キーワード:静的変数、メソッド、クラスをマスターする
  4. C# 抽象クラスと抽象メソッドをマスターする:実践ガイド
  5. C# 入れ子クラスを理解する:定義、使用法、継承
  6. C# 部分クラスと部分メソッドを理解する
  7. C++クラステンプレート完全ガイド:実践的なジェネリックプログラミング
  8. Java無名インナークラス完全ガイド:定義、構文、実践例
  9. Java ObjectOutputStream完全ガイド:シリアル化、メソッド、実践例
  10. Javaジェネリクス完全ガイド:再利用可能で型安全なコードの構築
  11. Javaファイル操作のマスター:java.ioによる作成・読み取り・書き込み・削除