ダイナミックバインディング
動的バインディング(英: dynamic binding)、遅延バインディング(英: late binding)[1]あるいは動的リンケージ(英: dynamic linkage)[2][3]は、コンピュータプログラミングにおいて、オブジェクトに対して呼ばれるメソッドあるいは引数を伴い呼び出される関数を、その名前に基づいて実行時に探索 (look up) するというメカニズムである。それぞれ動的束縛、遅延束縛、動的結合とも邦訳される。しかし、動的ディスパッチの意味でこれらの用語が使われることもある[2][4]。
対義語は静的バインディング(英: static binding)あるいは事前バインディング(英: early binding)であり、コンパイル時に確定する静的なオフセット情報などをもとにして関数実体のアドレスを取得する。
概要
[編集]静的型付けのプログラミング言語において、変数や式の型はコンパイル時に確定する。関数(メソッド)の存在確認は、コンパイル時にその名前(識別子)や引数リストの型、所属する名前空間および型などに基づいて事前に検査される。プログラマによって記述された関数呼び出しを、実際に関数が実装されているコードに一致させるプロセスのことをバインディングと呼ぶ[5]。
C++やJavaといった静的型付けのオブジェクト指向言語では、オブジェクトの型に基づいて実際に呼び出される関数(メソッド)が実行時に選択される「仮想関数」(仮想メソッド)を使った動的ディスパッチ(英: dynamic dispatch)によりポリモーフィズムを実現する。コンパイル時には、所望の関数を呼び出すためのアドレス情報が(バイナリ)プログラム内に仮想関数テーブルにおけるメモリオフセットとして保持される[5][6]。実行時に格納されたメモリオフセットすなわちアドレス情報(関数ポインタ)を使って所望の関数が呼び出される。この方式は、仮想関数テーブルの構造が事前に分かっているという点で、事前バインディングの一種である[5]。
遅延バインディングでは、コンパイラは仮想関数テーブルに所望の仮想関数が存在するかどうかを確認するために十分な情報を読み取らず、代わりに名前を用いて実行時にルックアップする。Component Object Model (COM) プログラミングにおける遅延バインディングの主要な利点は、コンパイラがオブジェクトの型情報を含むライブラリ(DLL)を参照する必要がないということである。名前ベースの柔軟なプログラミングが可能となることで、ライブラリのバージョン衝突に対してコンパイル処理に耐性がもたらされる[7]。遅延バインディングのデメリットとして、実行時に名前解決を試みるために、統合開発環境によるコード補完などの支援や、コンパイル時の静的な型チェック機構が働かず、実行時になって初めてプログラミングミスが発覚する可能性が高くなること、またコンパイラ最適化が働かず、オーバーヘッドが大きくなり実行速度が低下することが挙げられる[8]。
動的プログラミング言語のシンボル探索は基本的に名前ベースで、実行時に解決する動的バインディング方式である。ダック・タイピングも参照のこと。
動的ディスパッチの例
[編集]C++では以下のように仮想関数を派生クラスにてオーバーライドすることで、実際に呼び出される関数の実体をオブジェクトの型に応じて実行時に選択することができる。これを動的ディスパッチと呼ぶ。
#include <iostream>
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(Base& obj) {
obj.MemberFunc();
}
int main() {
Base b;
CallMemberFunc(b);
Derived d;
CallMemberFunc(d); // Base& で受け取って MemberFunc() を呼び出しているが、実際に呼ばれるのは Derived::MemberFunc() のほう。
}
仮想関数テーブルを利用した動的ディスパッチは、前述のように事前バインディングの一種であり、真の意味での動的バインディング/遅延バインディングとは異なる。しかし、動的ディスパッチの意味でこれらの用語が使われていることもある[2]。
遅延バインディングの例
[編集]VB.NETにおける遅延バインディングの例を示す。
Option Strict Off
Class SomeClass1
Public Sub SomeMethod
Console.WriteLine("SomeClass1.SomeMethod() is called.")
End Sub
End Class
Class SomeClass2
Public Sub SomeMethod
Console.WriteLine("SomeClass2.SomeMethod() is called.")
End Sub
End Class
Public Class LateBindingExample
Shared Sub CallSomeMethod(obj As Object)
' Option Strict On を指定するとコンパイルエラーになる。
obj.SomeMethod()
End Sub
Shared Function Main As Integer
CallSomeMethod(New SomeClass1())
CallSomeMethod(New SomeClass2())
Return 0
End Function
End Class
VB.NETにおけるObject
型は、.NETの基本クラス型System.Object
[9]であり、あらゆる型の最上位基底クラスであるが、Object
型自体には上記のSomeMethod
という名前を持つメソッドは定義されていない。しかし、Option Strict Off
を指定することで、コンパイル時にメソッドの存在有無を確認しなくなり、実行時に探索を試みる。これが遅延バインディングである。もし該当メソッドが見つからなかった場合、実行時に例外System.MissingMemberException
がスローされる[注釈 1]。
なお、VB.NETのコンパイラでは、デフォルトでOption Strict Off
となっており、遅延バインディングが許可されている[10]。
JavaやC#ではリフレクションを使って遅延バインディングを実現することもできる。C# 4.0以降はdynamic
型を使用した遅延バインディングも可能となっている[11]。Visual Basic .NET (VB.NET) ではOption Strict Off
によって遅延バインディングが可能である[12]。
Windows APIのGetProcAddress()
[13]や、POSIXのdlsym()
[14]は、関数名の文字列に基づいてモジュール内の関数ポインタを探索する。これらを使うことで、遅延バインディングを実現することもできる。
脚注
[編集]注釈
[編集]- ^ 内部的にはVB.NETのコンパイラサービスによる遅延バインディング機能Microsoft.VisualBasic.CompilerServices.LateBindingが使用されている。
出典
[編集]- ^ Booch, Grady. Object-oriented Analysis and Design. Addison-Wesley, 1994. p71
- ^ a b c Schreiner, Axel-Tobias (1994). Object-Oriented Programming With ANSI-C. Munich: Hanser. pp. 15. ISBN 3-446-17426-5
- ^ 動的リンク(dynamic linking)とは異なる。
- ^ Late Binding in Java - Stack Overflow
- ^ a b c Use early binding and late binding in Automation - Office | Microsoft Docs
- ^ “Using early binding and late binding in Automation”. Microsoft (2003年9月6日). 2014年6月27日時点のオリジナルよりアーカイブ。2014年6月27日閲覧。
- ^ .NET - COMの機能を使用する – IJCAD ヘルプセンター
- ^ 事前バインディングと遅延バインディング - Visual Basic | Microsoft Docs
- ^ Object Class (System) | Microsoft Docs
- ^ [Visual Basic の既定値] ([オプション] ダイアログ ボックス - [プロジェクト]) - Visual Studio (Windows) | Microsoft Docs
- ^ dynamic 型の使用 - C# プログラミング ガイド | Microsoft Docs
- ^ オブジェクト変数の宣言 - Visual Basic | Microsoft Docs
- ^ GetProcAddress | Microsoft Docs
- ^ dlsym | The Open Group Base Specifications Issue 7, 2018 edition | IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008)