为什么 Delphi 7 不允许扩展类型的 TList

Why doesn't Delphi 7 allow a TList of Extended type

我已经创建了几个简单的列表(以及整数列表和颜色列表),但是当我尝试制作一个 "extended" 列表时,它说类型转换无效,即使我对之前的 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;

IntegerTColor 与 Delphi 7 中的 Pointer 具有相同的大小(4 字节),这就是为什么显式转换是可能的。

docWiki:

Variable Typecasts
You can cast any variable to any type, provided their sizes are the same and you do not mix integers with reals.

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

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

有几个原因。首先,正如 MBo 在他的回答中已经写的那样,Extended 的大小为 10 个字节,因此它不适合 Pointer.

的 32 位(4 个字节)

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

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

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;

但这意味着您的 TList 现在包含 指针 Extended堆。因此删除或更改需要您使用

Dispose(P);

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

检索类似:

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 所说,您可以使用虚拟 Notify 函数来删除已删除的项目,而不是在每个方法中:

procedure TExtendedList.Notify(Ptr: Pointer; Action: TListNotification); // declare as override;
begin
  inherited;
  if Action = lnDeleted then
    Dispose(PExtended(Ptr));
end;