2

使用 Delphi 7,我有几个采用单个整数参数的函数。这些函数对属于该对象的文本字符串进行操作。唯一的参数是文本中的字符索引或单词索引。例如,要在单词 i 或字符 Text[loc] 之后检索 Text 的下一个单词,我想要:

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

显然,这是模棱两可的。Delphi Help 说“重载的例程必须通过它们采用的参数数量或参数类型来区分。” 所以我定义了两种类型:

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

但这不起作用,因为这些只是整数的别名。

Delphi 关于类型的帮助区分了“类型标识”、“类型兼容性”和“赋值兼容性”,然后没有说明如何使用这些区别。但它确实说要重复“类型”这个词来创建与整数不同的新类型:

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 参数,形式和实际的类型必须相同。”),但这没有帮助。

上网时,我读到编译器首先根据参数的数量,然后根据它们的大小来消除重载函数的歧义。我想我可以让 WordIndex 成为 DWord 而不是 Integer,但我不希望它是 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。即它们都是整数。

我的问题是,我应该这样做吗?如果是这样,我怎么会知道呢?帮助或源代码中是否有类似的示例?

奖励问题:我检查过,并且将类型 WordIndex 设置为 Range 不会在调用或函数中产生代码/运行时开销。但它可能在代码的其他地方吗?Delphi 会在不会测试整数的任何地方测试 WordNumber 的范围错误吗?(我很确定答案是否定的。)

4

2 回答 2

7

在这里尝试使用超载只会导致痛苦和痛苦。想象一下当你想使用整数文字时会发生什么?或者想象一下,您想向 NextWord 传递一个作为表达式的索引,例如 a+b。或者你传递一个函数的返回值。您是否将拥有返回您建议定义的各种专用类型的函数?想想任何必须阅读代码的人。他们将如何确定正在调用哪个重载?

你可以通过给你的函数起不同的名字来避免所有的痛苦。当您有多个接受不同类型参数的函数时,重载是合适的。这里情况不同。您的函数采用相同类型的参数。所以你的函数需要不同的名字。

组织它的另一种方法是拥有一个函数,但将更多传递给函数。传递索引和描述如何解释该索引的枚举类型。您可以将这两个值组合成一条记录。

于 2012-11-17T23:30:39.897 回答
1

如果遇到此类问题,请使用重构来分离不同的行为。例如,您可以按位置和字符索引拆分单词提取,您可以引入两个新类:

电话是:

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

另一种方法可能是使用第二个参数提供该方法:

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

但是,我建议重构。

于 2012-11-18T14:33:34.607 回答