如何为相互依赖的记录定义隐式转换运算符?

14

我在Delphi 2006中使用记录类型的运算符重载。(请不要告诉我不要这样做)

我有两个记录类型,都重载了隐式运算符。它们只存在于模块的实现部分,没有通过接口暴露出来。

我的问题是,现在它们相互依赖,我不知道如何向编译器前置声明第二种类型。我知道如何对函数、过程和类进行前置声明,但不知道如何对记录进行。

以下是我尝试做的简化示例:

implementation

type
  TMyRec1 = record
    Field1 : Integer;
    class operator Implicit(a: TMyRec2): TMyRec1;  // <---- Undeclared Identifier here.
  end;

  TMyRec2 = record
    Field2: Integer;
    class operator Implicit(a: TMyRec1): TMyRec2;
  end;

class operator TMyRec1.Implicit(a:TMyRec2): TMyRec1;
begin
  Result.Field1 := a.Field2;
end;

class operator TMyRec2.Implicit(a:TMyRec2): TMyRec2;
begin
  Result.Field2 := a.Field1;
end;

如果每种类型都可以隐式地转换为另一种类型,您可能需要重新考虑是否真的需要两种不同的类型。 - Rob Kennedy
@Rob: 这是很有可能的。最近我遇到了同样的情况,当我有两种不同的向量类型时,一个是整数类型,另一个是浮点类型。你需要这两种类型来做不同的事情,但你希望它们互相之间能够兼容赋值。解决方案基本上就像你发布的那个。 - Mason Wheeler
2
类型并不是如此简单。其中一个携带有关另一个的摘要统计信息。它们用于逻辑上分组传递到其他地方的数据。[重新发布以尝试消除多余的空格。] - Richard A
2个回答

14

记录类型不能进行前向声明。在第二个类型中定义Implicit运算符:

type
  TMyRec1 = record
    Field1 : Integer;
  end;

  TMyRec2 = record
    Field2: Integer;
    class operator Implicit(a: TMyRec2): TMyRec1;
    class operator Implicit(a: TMyRec1): TMyRec2;
  end;

引用自帮助文档:

只有在绝对必要的情况下才应提供隐式转换,应避免反射性。最好让类型B隐式转换为类型A,并且让类型A不了解类型B(或反之亦然)。


1
谢谢Rob。我猜这是显而易见的解决方案,但当你知道时它们都是如此。你为什么说应该避免隐式转换? - Richard A
1
我并没有说应该避免使用隐式转换。我只是引用了文档。但既然你问了,隐式转换可能会使代码更难阅读;当没有任何东西引起注意时,很难注意到发生的转换。我会使用普通函数将一种类型转换为另一种类型。或者你可以使用显式转换运算符。 - Rob Kennedy
谢谢。我应该更仔细地阅读。我只是匆忙浏览了一下帮助文件中引用的那部分。是的,我也有点担心运算符重载和隐式转换,但我会在小案例中尝试一下,看看效果如何。有趣的是,我曾经遇到过一些主要的性能问题,都是由于标准数字和字符串类型的隐式转换引起的。 - Richard A

3
你可能可以使用记录辅助函数来完成这个任务。
以下是我最近用来解决无法声明前向记录的问题的方法。
它使用了记录辅助函数构造,就像隐式类型转换一样,也有缺点。 最重要的一个是,仅会应用于特定记录类型的最近的记录辅助函数。
type
  TIpv4Address = record
  strict private
    FAddress: TIpv4Quad;
    FMask: TIpv4Quad;
  private
    class function CreateInternal(const IP_ADDR_STRING: _IP_ADDR_STRING): TIpv4Address; static;
  public
    class function Create(const IP_ADDR_STRING: _IP_ADDR_STRING): TIpv4Address; static;
    class function Count(const IP_ADDR_STRING: _IP_ADDR_STRING): Integer; static;
    property Address: TIpv4Quad read FAddress;
    property Mask: TIpv4Quad read FMask;
  end;

  TIpv4AddressList = array of TIpv4Address;

  TIpv4AddressHelper = record helper for TIpv4Address
    class function CreateList(const IP_ADDR_STRING: _IP_ADDR_STRING): TIpv4AddressList; static;
  end;

您可以这样使用它:
function TAdapterInfo.GetIpAddressList: TIpv4AddressList;
begin
  Result := TIpv4Address.CreateList(AdapterInfos.IP_ADAPTER_INFO[Index].IpAddressList);
end;

--jeroen


谢谢。我会看一下的。我之前不知道“记录助手”这个结构。 - Richard A
1
它在Delphi 2006中悄悄地引入了Win32和.NET版本。Class helpers是在Delphi 2005中为Win32引入的,而第一个Delphi .NET版本(许多人不想被提醒的版本号)也同样引入了这个特性。 - Jeroen Wiert Pluimers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接