アーリーバインディングとレイトバインディングとは何ですか?
On 11月 18, 2020 by adminバインディングの初期および遅延について聞き続けていますが、それらが何であるかわかりません。理解できない次の説明を見つけました。
アーリーバインディングとは設計時の変数への値の割り当てを指し、レイトバインディングとは値の割り当てを指します。実行時に変数に変換します。
2種類のバインディングを定義して比較していただけませんか?
コメント
- コンパイル時とランタイム。
- この件についてよく読んでください: en.wikibooks.org/ wiki / Introduction_to_Programming_Languages / …
回答
混乱には、バインディングとロードという2つの主要な概念があります。これは、DataBindingの概念によって混乱しています。DataBindingは、中間のどこかで両方を実行することがよくあります。検討した後、もう1つの概念を追加して、3連単を完成させ、ディスパッチします。
タイプ
遅延バインディング:実行時に変数が実行されるまで、タイプは不明です。通常は割り当てを通じてですが、型を強制する他の手段があります。動的型付け言語はこれを基本機能と呼びますが、多くの静的型付け言語にはレイトバインディングを実現する方法があります
[特別な]動的型、イントロスペクション/リフレクション、フラグ、コンパイラオプションを使用して、または仮想メソッドを介して実装されることがよくあります動的ディスパッチを借用および拡張することにより
早期バインディング:タイプは既知です実行時に変数が実行される前に、通常は静的で宣言的な手段を使用します
標準のプリミティブ型を使用して実装されることがよくあります
関数
静的ディスパッチ:コンパイル時の既知の特定の関数またはサブルーチン。明確で、署名と一致します
静的関数として実装されています。同じ署名を持つメソッドはありません
動的ディスパッチ:特定の関数ではありませんまたはコンパイル時のサブルーチン。実行中のコンテキストによって決定されます。 「動的ディスパッチ」には2つの異なるアプローチがあり、適切な関数実装を選択するために使用されるコンテキスト情報によって区別されます。
シングル [ dynamic ] dispatch 、インスタンスのタイプのみが適切な関数の実装を決定するために使用されます。静的に型付けされた言語では、これが実際に意味することは、変数が宣言/割り当てられたときに示された参照型に関係なく、インスタンス型が使用されるメソッド実装を決定することです。適切な実装を推測するために使用されるのは単一のタイプ(オブジェクトインスタンスのタイプ)のみであるため、このアプローチは「単一ディスパッチ」と呼ばれます。
複数 [動的] ディスパッチ。ここで、入力パラメータータイプは、呼び出す関数の実装を決定するのにも役立ちます。複数のタイプ(インスタンスのタイプとの両方)がパラメータのタイプに影響を与えるためどのメソッド実装が選択されるか、このアプローチは「多重ディスパッチ」と呼ばれます。
仮想関数または抽象関数として実装されます。他の手がかりには、オーバーライド、非表示、またはシャドウされたメソッドが含まれます。
NB: メソッドのオーバーロードに動的ディスパッチが含まれるかどうかは言語固有です。たとえば、Javaでは、オーバーロードされたメソッドは静的にディスパッチされます。
値
遅延読み込み:必要になるまで値の割り当てを延期するオブジェクト初期化戦略。オブジェクトを本質的に有効であるが、故意に不完全な状態にし、データが必要になるまで待ってからロードできるようにします。多くの場合、大きなデータセットの読み込みや外部リソースの待機に特に役立ちます
コンストラクターまたは初期化の呼び出し中に、ダウンストリームの呼び出し元がの内容を確認するように要求するまで、コレクションまたはリストを複合オブジェクトに意図的に読み込まないことで実装されます。そのコレクション(例:get_value_at、get_all_asなど)。バリエーションには、コレクションに関するメタ情報(サイズやキーなど)の読み込みが含まれますが、実際のデータは省略されます。また、一部のランタイムにメカニズムを提供して、開発者にかなり安全で効率的なシングルトン実装スキームを提供します
積極的な読み込み:オブジェクトの初期化戦略。すべての値の割り当てを即座に実行して、有効な状態であると見なす前にすべてのデータを完了する必要があります。
頻繁に実装されます。コンストラクターの呼び出し中や初期化中など、既知のすべてのデータを複合オブジェクトにできるだけ早く提供します
データのバインド:多くの場合、2つの互換性のある情報ストリーム間にアクティブなリンクまたはマップを作成して、一方への変更が他方に反映されるようにします。互換性を保つために、多くの場合、共通のベースタイプまたはインターフェイスが必要です。
さまざまなアプリケーションの側面(ビュー-モデルからビュー、モデルからコントローラーなど)間でよりクリーンで一貫性のある同期を提供するために、多くの場合実装されます。など)、ソースとターゲット、エンドポイント、バインド/バインド解除、更新などの概念、およびon_bind、on_property_change、on_explicit、on_out_of_scopeなどのイベントについて説明します
編集注:説明を提供するための最後の主要な編集これらがどのように頻繁に発生するかの例の例。特定のコード例は、実装/ランタイム/プラットフォームに完全に依存しています
コメント
- この回答はオブジェクト指向言語に固有すぎるようです。
- @Jack私は’このように感じていません。これは、多くの側面をカバーする優れた機能だと思います。
回答
コンパイル中にコンパイラによって決定されるものはすべて、初期/コンパイル時バインディングおよび RUNTIME で決定されるものはすべて LATE / RUNTIME バインディング。
たとえば、
メソッドオーバーロードとメソッドオーバーライド。
1 )メソッドのオーバーロードでメソッドがメソッドarを呼び出すどの関数が呼び出されるかは、コンパイル時にコンパイラによって決定されるという意味で、コンパイラによって決定されます。したがって、早期バインドです。
2)メソッドのオーバーライドでは、実行時にどちらのメソッドが決定されます。呼ばれる予定です。そのため、遅延バインディングと呼ばれます。
シンプルで簡単に入手できるようにしました。これがお役に立てば幸いです。
回答
遅延バインディングは、実行時に動作が評価されるときです。 「プログラムの実行時にのみ持っている情報に基づいて実際にどのように行動するかを決定したい場合に必要です。私の意見で最も明確な例は、特にC ++の仮想関数メカニズムです。
class A { public: void f() {} virtual void g() {} }; class B : public A { void f() {} virtual void g() {} }; int main() { A* a = new B; a->f(); a->g(); }
この例では、a->f()
は実際にはvoid A::f()
を呼び出します。これは、早い(または静的に)ためです。 )バインドされているため、実行時のプログラムは A
型変数へのポインタであると考えますが、a->g()
は実際にはvoid B::g()
を呼び出します。これは、コンパイラがg()
を仮想的に認識しているため、コードを挿入して正しい関数のアドレスを検索するためです。実行時に呼び出す。
コメント
- “実行時”?’はC ++について話しています。C++はマシンコードに直接コンパイルされます。’解決するためにランタイムは必要ありません。仮想メソッド。
- @tdammers C ++には、仮想呼び出し用ではありませんが、実際にはランタイムライブラリが必要です。注意深く読むと、’この回答は、コンパイラが”コードを挿入して正しい関数のアドレスを検索することを示していることに気付くでしょう[ …] at ランタイム”。
- まあ、でもその”コード正しい関数のアドレスを検索する”は、基本的に、型に依存しない2段階のポインター逆参照とそれに続く関数呼び出しです。 “思考”は関係ありません。確実に機能する唯一の理由は、コンパイラがコンパイル時に型チェックを行うためです。実行時に、生成されたコードは、コンパイラーが型チェックの宿題を行ったことを信頼します。安全でないキャストを使用する場合(例:Cスタイルのポインタキャスト)、C ++オブジェクトを間違ったクラスのオブジェクトとして合法的に扱うことはできますが、それらのvtableは完全に台無しになり、コードは壊れてしまいます。
- @tdammers ‘はコンパイラの実装の詳細であり、一部の難解なコンパイラには当てはまる場合と当てはまらない場合があるため、この種の回答は避けようとしました。重要なのはコンセプトです。
- @tdammersそして”ランタイム”は実行時のプログラム”。明らかに、C ++は’管理されていません。しかし、混乱を招く可能性があることを示したので、’完全な表現に変更します。
回答
関数ポインタに精通している場合、これは一例です。定義された関数は早期バインディングと言えます。一方、関数ポインタを使用する場合は、遅延バインディング。
int add(int x,int y) { return x+y; } int sub(int x,int y) { return x-y; } int main() { //get user choice int(*fp)(int,int); //if add fp=add; //else if sub fp=sub; cout<<fp(2,2); }
ここで、関数addとsubは関数です(そのアドレスはコンパイル時にバインドされます-リンカー)
しかし、関数ポインターは遅延していますfpのバインディングは、[実行時]のユーザーの選択に応じてaddまたはsubのいずれかを呼び出すことができます。
回答
アーリーバインディングとレイトバインディングのみタイプのコンテキストで意味があり、それを説明する方法ではありません。現代のほとんどすべての言語は、すべての値が固定型であるという意味で型付けされています。動的に型付けされた言語と静的に型付けされた言語を比較すると、違いが生じます。動的型付け言語では、変数には型がないため、任意の型の値を参照できます。つまり、ある変数によって参照されるオブジェクトでメソッドを呼び出す場合、その呼び出しが有効かどうかを判断する唯一の方法は、オブジェクトのクラスを検索し、そのメソッドが実際に存在するかどうかを確認します。これにより、実際のメソッド検索は最後の瞬間まで延期されるため、実行時にクラスに新しいメソッドを追加するなど、いくつかのクールなことが可能になります。ほとんどの人はこの状態を
静的に型付けされた言語では、変数には型があり、一度宣言すると、同じ型ではない値を参照することはできません。これは厳密には当てはまりませんが、今のところ想定しておきます。変数が特定のタイプの値のみを参照することがわかっている場合、コードが実行される前に有効性を判断できるため、実行時にメソッド呼び出しが有効かどうかを判断する理由はありません。これはアーリーバインディングと呼ばれます。
ルビーでレイトバインディングを示す例:
a = 1 # a is an integer at this point a.succ # asking for its successor is valid class A def method_a # some code end end a = A.new a.method_a # this is also valid a.succ # this is not valid class A # we can re-open the class and add a method def succ # some more code end end a.succ # now this is valid
上記の一連のアクションはそうではありません実行時にすべての型が修正されるJavaのような言語で可能です。
回答
学術的な定義を与える代わりにI VBAを使用した実際の例を使用して、いくつかの違いを示します。
アーリーバインディング:
Dim x As FileSystemObject Set x = New FileSystemObject Debug.Print x.GetSpecialFolder(0)
これには、設計時に「MicrosoftScriptingRuntime」コンポーネントへの参照を設定する必要があります。 FileSystemObject
またはGetSpecialFolder
のようなメソッド名にタイプミスがあると、コンパイル時にすでにエラーメッセージが表示されるという利点があります。
遅延バインディング
Dim x As Object Set x = CreateObject("Scripting.FileSystemObject") Debug.Print x.GetSpecialFolder(0)
これには、インスタンスの作成とタイプを事前に設定する必要はありません。決定は実行時に行われます。 x
の存在しないメソッドを呼び出そうとしても、コンパイラはコンパイル時に文句を言いません。これにより、特定の行が実行された場合にのみ実行時エラーが発生します。 。
したがって、遅延バインディングの欠点は、ここで強力な型チェックが行われないことです。ただし、これも利点です。たとえば、複数のバージョンが存在するコンポーネントがあり、新しいバージョンごとにいくつかの追加機能が提供されているとします(実際の例は、ExcelCOMインターフェイスなどのMSOfficeコンポーネントです)遅延バインディングにより、そのすべてのバージョンで動作するコードを記述します。最初に特定のコンポーネントバージョンを判別できます。使用できるのは古いバージョンのみであることがわかった場合は、そのバージョンで動作しない関数呼び出しを実行しないでください。
回答
実行時バインディングの最も一般的な例は、インターネットURLの解決です。世界中のすべてのサイトに到達する前にリンクやバインドを試みることなく、動的システムと大規模システムをサポートしますが、一方で、実行時にオーバーヘッド(DNSルックアップ、IPルーティングがはるかに少ない)が発生します。
その観点から、言語環境でのバインディングのほとんどの種類は、コンパイル時またはリンク時で、多かれ少なかれ早いです。
それぞれの種類にはコストとメリットがあります。
コメント
- このバインディングの定義のリファレンスをサイトに掲載できますか?インターネットアドレスを”バインディング”として解決することは聞いたことがありませんが、バインディングは名前を解決する行為であるため、誰かが主張したと思います アーリー/レイトバインディングの概念は、URIをインターネットアドレスに解決するために適用できること。 しかし、これは一般的な解釈ではなく、アーリー/レイトバインディングの概念は、コンピューターが一般的にインターネットに接続されていた時代よりも前のものです。
コメントを残す