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

时间:2017-06-21 18:10:26

标签: delphi casting tlist

当我尝试制作一个"扩展的"时,我已经创建了几个简单的列表(以及整数列表和颜色列表)。列出它表示无效的类型转换,即使我对前两个列表使用了类似的类型转换(无论我在何处使用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;

2 个答案:

答案 0 :(得分:8)

Delphi 7中IntegerTColor的大小(4个字节)都与Pointer相同,这就是显式转换的可能原因。

docWiki

  

变量Typecasts
  您可以将任何变量转换为任何类型,只要它们的大小相同即可   不要将整数与实数混在一起。

但是Extended是真实的,它的大小是10个字节,你不能把它强制转换为Pointer。而且,没有足够的地方。

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

答案 1 :(得分:3)

有几个原因。首先,正如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所说,您可以使用虚拟通知功能删除已删除的项目,而不是每种方法:

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