为什么德尔福 7 不允许扩展类型的 TList



我已经创建了几个简单的列表(以及整数列表和颜色列表),但是当我尝试制作"扩展"列表时,即使我对前 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的大小(4 字节)与 Delphi 7 中的Pointer相同,这就是为什么显式转换是可能的。

文档维基:

变量类型

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

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

附言请注意,新的德尔菲版本包含相当方便的工具 - 泛型 - 只需定义并创建TList<Extended>即可。

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

另一个原因是,在 Delphi 中,不允许将硬强制转换为浮点类型,因为太多的 C 程序员希望强制转换进行转换,而不仅仅是重新解释扩展(或其他浮点类型)的字节。尽管大小匹配,但也不允许投射到Single。如果我没记错的话,德尔福的早期版本确实允许这些演员(或者那是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所说,您可以使用虚拟通知功能删除已删除的项目,而不是在每个方法中:

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

最新更新