オーバーロードは、複数の実装でメソッド名をオーバーロードするプログラミング技術です。
たとえば、CalculateBill というメソッドがあり、購入品のリストをパラメーターとして取るとします。また、このメソッドの変化形を使用できます。この変化形には、購入品のリストの他に割引コードを表す別のパラメーターがあります。2 つのメソッドでは同じ名前を使用できます。メソッドを呼び出すと、割引コードのパラメーターの有無に基づき必要なメソッドが選択されます。
.NET COBOL では、指定のクラスやインターフェイスが同じ名前のメソッドを複数使用することが許可されており (非常に一般的な方法)、シグネチャを別にすることでそれぞれが区別されます。メソッドのシグネチャは、次の内容で決まります。
COBOL (またはその他の言語) で記述されたコードでクラスやインターフェイスのメソッドが呼び出される際に、その名前のメソッドが複数存在する場合は、利用可能なメソッドが選択されます。この選択は、パラメーターの数、およびパラメーターの型の「最適な」一致に基づいて行われます。適切なシグネチャのメソッドが見つからない場合、「method not found」(メソッドが見つからない) エラーが生じます。この名前が付いた他のすべてのメソッドよりも適切な一致を提供するメソッドがない場合、「ambiguous match」(曖昧な一致) エラーが表示されます。
RETURNING 項目の型はメソッドのシグネチャの一部ですが、呼び出されるメソッドが RETURNING 型に基づいて選択されることはありません。これは .NET および JVM との相違点であり、.NET および JVM では、クラスで RETURNING 型だけが異なるメソッドを複数使用できます。これは、一般的に適切な方法ではありません。単一クラス内でこのようなメソッドが複数見つかった場合、COBOL でエラーが生成されます。このような複数のメソッドが COBOL プログラムで生じるのは、明示的な演算子と暗黙的な演算子の場合のみです。
COBOL パラメーターの型は、次の方法で指定できます。
参照パラメーターおよび出力パラメーターの場合、マネージ型は、相当するマネージ型へのマネージ ポインターとして直接公開されます。マネージ型に相当しない COBOL データ型 (PIC X フィールド、グループ、BINARY-LONG 以外の数値フィールドなど) は、COBOL ポインター (.NET COBOL では MicroFocus.COBOL.Program.Reference 型のオブジェクト) として公開されます。
値パラメーターおよび RETURNING 項目の場合、型は次のように公開されます。
COBOL 型: | 公開される形態: |
---|---|
マネージ型 | 対応する型のオブジェクト |
小数桁が 19 を超える数値項目 | MicroFocus.COBOL.Program.BigDecimal |
すべてのサイズの、暗黙の小数点の数値項目 (PIC 9(9)v99 など) | - System.Decimal (.NET COBOL) |
暗黙の小数点のない符号なし数値項目: | .NET COBOL:
JVM COBOL では、これらは符号付き数値項目と同様に公開されます。 |
暗黙の小数点のない符号付き数値項目: |
|
他のすべての型の PIC X、グループなど | 文字列 |
メソッドのオーバーロードの解決は次の 2 つの段階で行われます。
形式的には、適用できるどのメソッドのオーバーロードよりも適切なメソッドのオーバーロードが選択されます。他のどのオーバーロードよりも適切と判断される 1 つのオーバーロードがない場合、一致は曖昧と見なされ、コンパイラでエラーが生じます。
この 2 段階のプロセスで一意の最適な一致が生じない場合、エラー (曖昧な一致エラー) が生成されます。
この説明では、引数という用語は、呼び出しメソッドで指定されるパラメーターのセットになります (例:次の文における obj01)。
INVOKE Method1(obj01)
パラメーターという用語は、各メソッドの定義 (PROCEDURE DIVISION USING ヘッダー内) で指定される形式的なパラメーターになります。
まず、ターゲット クラスまたはその親クラスのいずれかに存在する、必要な名前のメソッド一式 (同一シグネチャのメソッドを除く) から開始します。この一式から、メソッドにエンコードされる可視性属性に基づいて、呼び出し元のプログラムで表示できないメソッドは、次のように破棄されます。
属性 | 可視性 |
---|---|
PRIVATE | 呼び出しクラスがターゲット クラスと同じ場合のみ表示可能 |
PUBLIC | 常に表示可能 |
PROTECTED | 呼び出しクラスがターゲット クラスから派生する場合のみ表示可能 |
INTERNAL | ターゲット クラスが呼び出しクラスと同じアセンブリ内にある場合のみ表示可能 |
PROTECTED INTERNAL | 呼び出しクラスがターゲット クラスから派生する場合、または呼び出しクラスがターゲットと同じアセンブリ内にある場合のみ表示可能 |
次に、必要なメソッドがインスタンス メソッド (オブジェクト インスタンスに適用されるメソッド) の場合、すべての静的メソッドが破棄されます。同様に、必要なメソッドが静的メソッドの場合、すべてのインスタンス メソッドが破棄されます。
ここで、各メソッドを順番に調べ、通常の形式で適用できるかどうかを判断します。これは次のように決定されます。
参照パラメーターまたは出力パラメーターの場合、引数のタイプは、パラメーターのタイプと正確に同じでなければなりません。
値パラメーターの場合、暗黙変換が、引数のタイプから、対応するパラメーターのタイプに存在する必要があります。このような暗黙変換で切り捨てが必要な場合、このメソッドは切り捨て一致となります。
メソッドがこれらのルールに従って適用できない場合、拡張形式でのメソッドの一致が確認されます。どちらの場合も、次の内容が当てはまります。
メソッドの拡張形式は、配列パラメーターを、配列要素と同じタイプのゼロ個以上の値パラメーターで置き換えることで通常の形式から派生します。このため、パラメーターの総数は、呼び出し引数の数と同じになります。クラスに同じ拡張シグネチャのメソッドが通常形式ですでに含まれる場合、このメソッドは適用不可と判断されます。それ以外の場合、拡張形式は、上記の通常形式のテストと同様に適用可能かどうかのテストが行われます。
上記の選択手順後:
ambiguous match
method not found
引数タイプのセット (A1、A2、…An) の引数リスト A があり、2 つの適用可能なメソッドがパラメーター タイプ (P1…Pn) および (Q1、…Qn) の Mp と Mq をオーバーロードするとします。この場合、パラメーターは必要に応じて拡張形式に変換されています (上記参照)。
次に、Mp は Mq よりも適切なメソッドのオーバーロードであると言えます。どちらの場合も次の内容が当てはまります。
2 つの変換 (タイプ S からタイプ T1 およびタイプ S から T2) があるとします。T1 および T2 が次のような場合、T1 の方が適切な変換になります。
T1: | T2 が次のいずれかの場合: |
S と同じ | すべて |
binary-char |
|
binary-short |
|
binary-long |
|
binary-double |
|
それ以外の場合、どちらの変換も適切ではありません。
次の例では、提供される引数がターゲット メソッドの引数と正確に同じではない場合でも、最も固有のルールが実施される方法を示します。
class-id Class1 static. method-id main static. 01 objAnyObject object. 01 objString string. 01 objDateTime type DateTime. *> .NET COBOL * 01 objDateTime type java.util.Date. *> JVM COBOL 01 ref1 type Class1. procedure division. set ref1 to new Class1 invoke ref1::method1 *> uses variant 1 invoke ref1::method1(objAnyObject) *> uses variant 2 invoke ref1::method1(objString) *> uses variant 3 invoke ref1::method1(objDateTime) *> also uses variant 2, *> because an object of type DateTime can be assigned *> to an Object but not to a String. end method. method-id method1. *> Variant 1 (no parameters) procedure division. display "variant 1" end method. method-id method1. *> Variant 2 (object parameter) procedure division using by value objAnyObject as object. display "variant 2" end method. method-id method1. *> Variant 3 (string parameter) procedure division using by value objString as string. display "variant 3" end method. end class.
暗黙変換は、型 T のオブジェクトに型 S のオブジェクトを割り当てることができる場合、型 S から型 T に存在します。次の文に相当します。
SET obj-T TO obj-S
次の型の暗黙変換を利用できます。
これは、S が T と同じ型であることを意味します。
COBOL では、通常、数値項目を他の項目に割り当てることができますが、データの損失はユーザーの責任になります。ただし、変換が存在するかどうかをメソッドのオーバーロードのために判断する場合には、適切な変換と切り捨て変換を区別します。適切な変換とは、固定小数点と浮動小数点との間の変換で精度が失われる可能性はあってもデータの大きさは失われない変換のことです。
.NET COBOL 型の場合、適切な暗黙変換は次のようになります。
binary-char |
|
binary-char unsigned |
binary-char と同じ、次の内容を追加:
|
binary-short |
|
binary-short unsigned |
binary-short と同じ、次の内容を追加:
|
binary-long |
|
binary-long unsigned |
binary-long と同じ、次の内容を追加:
|
binary-double |
|
binary-double unsigned |
binary-double と同じ |
character |
|
float-short |
|
値 0 は、どの列挙型にも変換できます。
S と T が参照型の場合、次の状況で S を T に割り当てることができます。
ボックス化と呼ばれるプロセスで、どの値型も System.Object 型に変換できます。このプロセスの一環で、値はオブジェクト ヒープにコピーされ、参照が作成されます。
どの数値定数も、その定数のすべての値を含むことができる型に変換できます。たとえば、値 1 は、BINARY-CHAR UNSIGNED と BINARY-CHAR のどちらにも変換できます。
ユーザー定義の暗黙変換は、S から S1 へのオプションの暗黙数値変換、結果が T1 になるユーザー定義の暗黙変換演算子の実行、T へのもう 1 つのオプションの暗黙数値変換の順で構成されます。ユーザー定義の暗黙変換演算子は、OPERATOR-ID IMPLICIT を使用して COBOL で定義され、op_Implicit という名前のメソッドが結果として作成されます。