我有一个关于使用运算符重载转换类型的问题,这里我有一个完整的示例代码:
program OVerloads;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
TMyRange = record
private type
TMyRangeEnum = 1 .. 90;
var
FMyRangeEnum: TMyRangeEnum;
public
class operator Implicit(const Value: Integer): TMyRange;
class operator Implicit(const Value: TMyRange): Integer;
class operator Explicit(const Value: Integer): TMyRange;
class operator Explicit(const Value: TMyRange): Integer;
end;
class operator TMyRange.Implicit(const Value: Integer): TMyRange;
begin
Result.FMyRangeEnum := Value;
end;
class operator TMyRange.Implicit(const Value: TMyRange): Integer;
begin
Result := Value.FMyRangeEnum;
end;
class operator TMyRange.Explicit(const Value: Integer): TMyRange;
begin
Result.FMyRangeEnum := Value;
end;
class operator TMyRange.Explicit(const Value: TMyRange): Integer;
begin
Result := Value.FMyRangeEnum;
end;
var
MyValue: TMyRange;
MyVar: TMyRange; // (or Integer, not change nothing)
MyArr: array[1..90] of TMyRange; // (or Integer, not change nothing)
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
MyValue := 90;
Writeln(MyValue); // [1] Not work, error: E2054 Illegal in Write/Writeln statement
Writeln(Integer(MyValue)); // Work
MyVar := MyArr[MyValue]; // Not work, error: E2010 Incompatible types: 'Integer' and 'TMyRange'
MyVar := MyArr[Integer(MyValue)]; // work
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
可能我忘了一些东西,但是因为我可以在mnode中解决问题[1],不需要显式的所有时间整数(myValue)? 再次感谢,非常感谢。
答案 0 :(得分:3)
你似乎过于复杂了。定义这样的范围类型:
type
TMyRange = 1..90;
然后像这样声明你的数组:
var
MyArr: array[TMyRange] of TMyRange;
就是这样。
无论出于何种原因,您断言您需要在此处使用运算符重载的记录。尽管如此,但你已经确定运算符重载隐式强制转换不能用于鞋拔你的类型以与Writeln
和整数数组索引兼容。我找不到任何描述这些场景的文档,但很明显编译器不会让你做你想做的事。
据我所知,你可以依赖实际参数的隐式强制转换和赋值语句的右侧。
这是我演示选项的最小样本:
program Overloads;
{$APPTYPE CONSOLE}
type
TRec = record
private
function GetOrd: Integer;
public
class operator Implicit(const Value: TRec): Integer;
property ord: Integer read GetOrd;
end;
class operator TRec.Implicit(const Value: TRec): Integer;
begin
Result := 0;
end;
function TRec.GetOrd: Integer;
begin
Result := 0;
end;
procedure Foo(i: Integer);
begin
end;
var
R: TRec;
a: array[0..0] of Integer;
begin
Writeln(R);//E2054 Illegal type in Write/Writeln statement
Writeln(Integer(R));//explicit cast, provided by class operator Implicit
Writeln(R.ord);//my preferred option, a property
a[R] := 0;//E2010 Incompatible types: 'Integer' and 'TRec'
a[Integer(R)] := 0;//again, explicit cast is fine
a[R.ord] := 0;//or using a property
Foo(R);//implicit cast used for actual parameters
end.
备注:
答案 1 :(得分:0)
我不相信隐式运算符在Write / WriteLn中工作,因为它们是编译器魔术函数而不是采用特定类型的“正确”函数。
答案 2 :(得分:0)
我看到的唯一方法是重载Writeln函数:
procedure Writeln(wrt: Variant);
begin
System.Writeln(wrt);
end;
您必须更改异常处理程序以使用System.Writeln
或连接字符串,因为Delphi函数不支持打开参数计数。
修改强>
就像你在评论中提到的那样,在尝试将记录用作数组索引时会出现错误。
这是因为数组索引以及其他一些结构(例如循环变量和case
开关)需要序数类型(例如Integer
,Byte
,{{1} } ...)
传递记录在那里不起作用,因为记录不是序数类型。将其转换为序数类型的可能性并不一定。
有一个简单的解决方案:
将Word
定义为独立类型,没有包含它的记录
这不仅可以解决您遇到的问题,还可以解决您尚未遇到的问题:
TMyRangeEnum
将导致编译器错误,而不是将枚举变量设置为无效值。
同样会:
MyValue := 91;
导致出现这样的错误,而不是溢出(将分配0,这也不是枚举中的有效值。)