2

Delphi 7を使用して、単一の整数パラメーターを受け取るいくつかの関数があります。これらの関数は、オブジェクトに属するテキスト文字列を操作します。唯一のパラメータは、テキスト内の文字インデックスまたは単語インデックスのいずれかです。たとえば、単語iの後または文字Text [loc]の後のテキストの次の単語を取得するには、次のようにします。

function NextWord(i:Integer): String; overload;
function NextWord(loc:Integer): String; overload;

明らかに、これはあいまいです。Delphiヘルプによると、「オーバーロードされたルーチンは、使用するパラメーターの数またはパラメーターのタイプによって区別する必要があります。」そこで、2つのタイプを定義しました。

type WordIndex = Integer;
type CharIndex = Integer;
...
function NextWord(i:WordIndex): String; overload;
function NextWord(i:CharIndex): String; overload;

ただし、これらはIntegerの単なるエイリアスであるため、これは機能しません。

タイプに関するDelphiヘルプは、「タイプID」、「タイプ互換性」、および「割り当て互換性」を区別し、その区別の使用方法については何も述べていません。しかし、「type」という単語を繰り返して、Integerと同一ではない新しいタイプを作成すると言っています。

type WordIndex = type Integer;    //really, a new type
type CharIndex = type Integer;
...
function NextWord(i:WordIndex): String; overload;
function NextWord(i:CharIndex): String; overload;
...
var WordNumber: WordIndex;      //variable of new type
...
  WordStr := NextWord(WordNumber);  //call overloaded function

驚いたことに、これも機能しません。コンパイラはWordIndexを別の型として認識し、オーバーロードされた関数をコンパイルしますが、呼び出された場合、オーバーロードはあいまいであると主張します。また、関数パラメーターをVARに変更しようとしましたが(「varパラメーターの場合、形式パラメーターと実際のタイプは同一でなければならないため」)、それは役に立ちませんでした。

Webにアクセスすると、コンパイラーは、最初にパラメーターの数に基づいて、次にパラメーターのサイズに基づいて、オーバーロードされた関数を明確にすることを読みました。WordIndexを整数ではなくDWordにすることもできると思いますが、16ビットにはしたくないので、-1を使用して「無効な単語番号」を意味します。

最後に、「プロシージャと関数のオーバーロード」のヘルプでこれを見つけました。「ルーチンの宣言のいずれかとタイプが同じではないが、のパラメータと割り当て互換性のあるオーバーロードされたルーチンパラメータに渡すことができます。複数の宣言。...これらの場合、曖昧さなしにそうすることが可能であるとき、コンパイラーは、パラメーターが呼び出しの実際のパラメーターに対応する最小範囲のタイプであるルーチンを呼び出します。」

だから私はこれを試しました、それはうまくいきます:

type WordIndex = -1..High(Integer);
type CharIndex =  Integer;
function NextWord(i:WordIndex): String; overload;
function NextWord(i:CharIndex): String; overload;
...
var WordNumber: WordIndex;
    loc: CharIndex;
...
  WordStr := NextWord(WordNumber);
  (or)
  WordStr := NextWord(loc);

これは警告やエラーなしでコンパイルされ、実際には各パラメータータイプに対して正しい関数を呼び出します。また、SizeOf(WordIndex)= SizeOf(CharIndex)=4です。IEは両方とも整数です。

私の質問は、これは私がそれを行うことになっている方法ですか?もしそうなら、どうやってそれを知ることになったのですか?ヘルプやソースにそのような例はありますか?

ボーナスの質問:チェックしたところ、タイプWordIndexを範囲にすると、呼び出しや関数でコード/ランタイムのオーバーヘッドが発生しません。しかし、それはコードの他の場所にあるのでしょうか?Delphiは、整数をテストしない場所で、範囲エラーについてWordNumberをテストしますか?(答えは「いいえ」だと確信しています。)

4

2 に答える 2

7

ここでオーバーロードを使おうとすると、痛みと苦しみにつながります。整数リテラルを使用したいときに何が起こるか想像してみてください。または、NextWordに式であるインデックス(例:a + b)を渡したいと想像してください。または、関数の戻り値を渡します。定義することを提案するさまざまな専用タイプを返す関数を用意しますか?そして、コードを読まなければならない人間について考えてみてください。どのオーバーロードが呼び出されているかをどのように判断することが期待されますか?

関数に異なる名前を付けることで、すべての苦痛を回避できます。オーバーロードは、異なるタイプのパラメーターを受け取る複数の関数がある場合に適しています。ここではそうではありません。関数は同じタイプのパラメーターを取ります。したがって、関数には異なる名前が必要です。

それを整理する別の方法は、単一の関数を持つことですが、関数にもっと渡すことです。インデックスと、そのインデックスの解釈方法を説明する列挙型を渡します。これらの2つの値を1つのレコードに組み合わせることができます。

于 2012-11-17T23:30:39.897 に答える
1

このタイプの問題が発生した場合は、リファクタリングを使用してさまざまな動作を分離してください。たとえば、単語の抽出を場所と文字インデックスで分割したり、2つの新しいクラスを導入したりできます。

呼び出しは次のようになります。

MyClass.Location.NextWord(SomeIndex);
MyClass.Character.NextWord(SomeIndex);

別のアプローチは、2番目のパラメーターを使用してメソッドを提供することです。

MyClass.NextWord(SomeWordIndex, wmiByWordLocation);
MyClass.NextWord(SomeCharIndex, wmiByCharLocation);

ただし、リファクタリングをお勧めします。

于 2012-11-18T14:33:34.607 に答える