2

我已经创建了几个简单的列表(以及整数列表和颜色列表),但是当我尝试创建一个“扩展”列表时,它说无效的类型转换,即使我对前两个列表使用了类似的类型转换(它在任何地方都会抛出错误我使用 Extended() 类型转换)。

Type
  TAExtList = Class(TObject)
  Private
    FList: TList;
    Procedure SetExt(Index: Integer; Value: Extended);
    Function GetCnt: Integer;
    Function GetExt(Index: Integer): Extended;
  Public
    Constructor Create;
    Destructor Destroy; Override;
    Function Add(Value: Extended): Integer;
    Function Insert(Index: Integer; Value: Extended): Integer;
    Procedure Delete(Index: Integer);
    Procedure Clear;
    Function IndexOf(Value: Extended): Integer;
    Property Count: Integer Read GetCnt;
    Property Extendeds[Index: Integer]: Extended Read GetExt Write SetExt; Default;
  End;

Function TAExtList.Add(Value: Extended): Integer;
Begin
  Result := FList.Add(Pointer(Value));
End;
4

2 回答 2

8

两者都Integer具有与 Delphi 7TColor相同的大小(4 个字节)Pointer,这就是为什么可以进行显式转换的原因。

文档维基

变量类型转换
您可以将任何变量转换为任何类型,只要它们的大小相同,并且不要将整数与实数混合。

Extended它是真实的,它的大小是 10 字节,你不能将它转换为Pointer. 而且,没有足够的地方放它。

PS 请注意,新的 Delphi 版本包含相当方便的工具 - 泛型 - 只需定义和创建TList<Extended>

于 2017-06-21T18:24:32.693 回答
3

有几个原因。首先,正如 MBo 在他的回答中已经写的那样, anExtended的大小为 10 个字节,因此它不适合 a 的 32 位(4 个字节)Pointer

另一个原因是在 Delphi 中,不允许直接硬转换为浮点类型,因为太多的 C 程序员希望转换进行转换,而不仅仅是重新解释扩展(或其他浮点类型)的字节。尽管大小会匹配,Single但也不允许转换为。如果我没记错的话,非常早期的 Delphi 版本确实允许这些转换(或者是 Turbo Pascal?)。

但是你仍然可以创建你的TExtendedList, 如果你使用指针Extended毕竟, aTList存储指针):

type
  PExtended = ^Extended;

function TExtendedList.Add(const E: Extended): Integer;
var
  P: PExtended;
begin
  New(P);       // allocate an Extended on the heap and "return" a pointer to it
  P^ := E;      // store the parameter on the heap
  inherited Add(P); // add the pointer to the list
end;

但这意味着您的TListnow 包含指向Extended在堆上分配的 s 的指针。所以删除或更改需要您使用

Dispose(P);

在适当的地方(例如 in Delete(), Remove(), Extract(), Clear, 等和析构函数)。每个分配Extended的 s 都必须在正确的时间处理掉。

检索类似:

function TExtendedList.GetExt(Index: Integer): Extended;
var
  P: PExtended;
begin
  P := inherited Items[Index]; 
  Result := P^;
  // or short form: Result := PExtended(inherited Items[Index])^;
end;

procedure TExtendedList.SetExt(Index: Integer; Value: Extended);
var
  P: PExtended;
begin
  P := inherited Items[Index];
  P^ := Value;
  // or short form: PExtended(inherited Items[Index])^ := Value;
end;

procedure TExtendedList.Delete(Index: Integer);
begin
  Dispose(PExtended(inherited Items[Index]));
  inherited Delete(Index);
end;

procedure TExtendedList.Clear;
var
  I: Integer;
begin
  for I := 0 to Count - 1 do
    Dispose(PExtended(inherited Items[I]));
  inherited Clear;
end;    

等等等等……

更新

正如@kobik 所说,您可以使用虚拟通知功能来删除已删除的项目,而不是在每个方法中:

procedure TExtendedList.Notify(Ptr: Pointer; Action: TListNotification); // declare as override;
begin
  inherited;
  if Action = lnDeleted then
    Dispose(PExtended(Ptr));
end;
于 2017-06-21T19:11:03.530 回答