ダイナミックバインディング

動的バインディング、遅延バインディングあるいは動的リンケージは、コンピュータプログラミングにおいて、オブジェクトに対して呼ばれるメソッドあるいは引数を伴い呼び出される関数を、その名前に基づいて実行時に探索  するというメカニズムである。それぞれ動的束縛、遅延束縛、動的結合とも邦訳される。しかし、動的ディスパッチの意味でこれらの用語が使われることもある。

対義語は静的バインディングあるいは事前バインディングであり、コンパイル時に確定する静的なオフセット情報などをもとにして関数実体のアドレスを取得する。

1. 概要
-----

静的型付けのプログラミング言語において、変数や式の型はコンパイル時に確定する。関数の存在確認は、コンパイル時にその名前や引数リストの型、所属する名前空間および型などに基づいて事前に検査される。プログラマによって記述された関数呼び出しを、実際に関数が実装されているコードに一致させるプロセスのことをバインディングと呼ぶ。

C++やJavaといった静的型付けのオブジェクト指向言語では、オブジェクトの型に基づいて実際に呼び出される関数が実行時に選択される「仮想関数」を使った動的ディスパッチによりポリモーフィズムを実現する。コンパイル時には、所望の関数を呼び出すためのアドレス情報がプログラム内に仮想関数テーブルにおけるメモリオフセットとして保持される。実行時に格納されたメモリオフセットすなわちアドレス情報を使って所望の関数が呼び出される。この方式は、仮想関数テーブルの構造が事前に分かっているという点で、事前バインディングの一種である。

遅延バインディングでは、コンパイラは仮想関数テーブルに所望の仮想関数が存在するかどうかを確認するために十分な情報を読み取らず、代わりに名前を用いて実行時にルックアップする。Component Object Model  プログラミングにおける遅延バインディングの主要な利点は、コンパイラがオブジェクトの型情報を含むライブラリを参照する必要がないということである。名前ベースの柔軟なプログラミングが可能となることで、ライブラリのバージョン衝突に対してコンパイル処理に耐性がもたらされる。遅延バインディングのデメリットとして、実行時に名前解決を試みるために、統合開発環境によるコード補完などの支援や、コンパイル時の静的な型チェック機構が働かず、実行時になって初めてプログラミングミスが発覚する可能性が高くなること、またコンパイラ最適化が働かず、オーバーヘッドが大きくなり実行速度が低下することが挙げられる。

動的プログラミング言語のシンボル探索は基本的に名前ベースで、実行時に解決する動的バインディング方式である。ダック・タイピングも参照のこと。

2. 動的ディスパッチの例
-------------

C++では以下のように仮想関数を派生クラスにてオーバーライドすることで、実際に呼び出される関数の実体をオブジェクトの型に応じて実行時に選択することができる。これを動的ディスパッチと呼ぶ。

include class Base { public: // 基底クラスにて virtual 指定を外すと、動的ディスパッチではなくなる。 virtual void MemberFunc { std::cout << "Base::MemberFunc is called." << std::endl; } };

class Derived : public Base { public: // 派生クラスでの virtual 指定の有無は、オーバーライドとは無関係。 // C++11 規格以降は override キーワードを後置することで、正しくオーバーライドされているかどうかコンパイラにチェックさせることもできる。 virtual void MemberFunc { std::cout << "Derived::MemberFunc is called." << std::endl; } };

// Base クラスから派生していない型のインスタンスを Base& で受け取ることはできない。コンパイラの静的な型チェックによりエラーとなる。 // つまり、MemberFunc の存在有無は静的に検証される。 void CallMemberFunc { obj.MemberFunc; }

int main { Base b; CallMemberFunc; Derived d; CallMemberFunc; // Base& で受け取って MemberFunc を呼び出しているが、実際に呼ばれるのは Derived::MemberFunc のほう。 }<WtXmlEndTag />

仮想関数テーブルを利用した動的ディスパッチは、前述のように事前バインディングの一種であり、真の意味での動的バインディング／遅延バインディングとは異なる。しかし、動的ディスパッチの意味でこれらの用語が使われていることもある。

3. 遅延バインディングの例
--------------

VB.NETにおける遅延バインディングの例を示す。 Option Strict Off

Class SomeClass1 Public Sub SomeMethod Console.WriteLine is called.") End Sub End Class

Class SomeClass2 Public Sub SomeMethod Console.WriteLine is called.") End Sub End Class

Public Class LateBindingExample Shared Sub CallSomeMethod ' Option Strict On を指定するとコンパイルエラーになる。 obj.SomeMethod End Sub

Shared Function Main As Integer CallSomeMethod) CallSomeMethod) Return 0 End Function End Class<WtXmlEndTag />

VB.NETにおけるObject型は、.NETの基本クラス型System.Objectであり、あらゆる型の最上位基底クラスであるが、Object型自体には上記のSomeMethodという名前を持つメソッドは定義されていない。しかし、Option Strict Offを指定することで、コンパイル時にメソッドの存在有無を確認しなくなり、実行時に探索を試みる。これが遅延バインディングである。もし該当メソッドが見つからなかった場合、実行時に例外System.MissingMemberExceptionがスローされる。

なお、VB.NETのコンパイラでは、デフォルトでOption Strict Offとなっており、遅延バインディングが許可されている。

JavaやC#ではリフレクションを使って遅延バインディングを実現することもできる。C# 4.0以降はdynamic型を使用した遅延バインディングも可能となっている。Visual Basic .NET  ではOption Strict Offによって遅延バインディングが可能である。

Windows APIのGetProcAddressや、POSIXのdlsymは、関数名の文字列に基づいてモジュール内の関数ポインタを探索する。これらを使うことで、遅延バインディングを実現することもできる。

4. 脚注
-----

4.1. 注釈
-------

4.2. 出典
-------

5. 関連項目
-------

動的プログラミング言語
ダック・タイピング
束縛