I've created several simple lists (and integer list and color list) yet when I try to make an "extended" list it says invalid typecast even though I've used similar typecasting for the prior 2 lists (it throws the error wherever I use the Extended() typecast).
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;
There are several reasons. First, as MBo already wrote in his answer, an Extended
is 10 bytes in size, so it doesn't fit in the 32 bits (4 bytes) of a Pointer
.
Another reason is that in Delphi, direct hard casts to floating point types are not allowed, because too many C programmers expected the cast to do a conversion, instead of just a reinterpretation of the bytes of the Extended (or other floating point type). Although the sizes would match, casting to Single
is not allowed either. Very early versions of Delphi did actually allow these casts, if I remember correctly (or was that Turbo Pascal?).
But you can still create your TExtendedList
, if you use pointers to Extended
(after all, a TList
stores pointers):
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;
But this means that your TList
now contains pointers to Extended
s that are allocated on the heap. So removing or changing requires you to use
Dispose(P);
at the appropriate places (e.g. in Delete()
, Remove()
, Extract()
, Clear
, etc. and the destructor). Each of the allocated Extended
s must be disposed of at the right time.
Retrieving is similar:
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;
Etc., etc. ...
As @kobik said, you could use the virtual Notify function to delete the items that are removed, instead of in each method:
procedure TExtendedList.Notify(Ptr: Pointer; Action: TListNotification); // declare as override;
begin
inherited;
if Action = lnDeleted then
Dispose(PExtended(Ptr));
end;