I'm experimenting with Delphi 10 Seattle and trying to create my first Generic Container class. I need help with a Generic Comparer
Here a simple Hash object which I created:
type
TsmHeap<T> = class
private
fList: TList<T>;
Comparer: TComparer<T>;
procedure GetChildren(ParentIndex: integer; var Child1, Child2: integer);
function GetParent(ChildIndex: integer): integer;
function GetCapacity: integer;
function GetCount: integer;
function MustSwap(iParent, iChild: integer): boolean;
procedure SetCapacity(const Value: integer);
public
constructor Create(aComparer: TComparer<T>); overload;
constructor Create(aComparer: TCOmparer<T>; aCapacity: integer); overload;
destructor Destroy; override;
//-- Methods & Functions
function Dequeue: T;
procedure Enqueue(Item: T);
function IsEmpty: boolean;
//-- Properties
property Count: integer read GetCount;
property Capacity: integer read GetCapacity write SetCapacity;
end;
I've write the code for the methods and it compiles on its own with no problems. However when I try to create an integer version of the class I cannot get it to compile.
The problematic code is:
iHeap := TsmHeap<integer>.Create(TComparer<integer>.Construct(
function(const Left, Right: integer): integer
begin
result := Sign(Left - Right);
end)
);
This give a "E2250 There is no overloaded version of 'Create' that can be called with these arguments"
What am I doing wrong? How do I create the Comparer?
TComparer<T>.Construct returns IComparer<T> - it is a class function and not a constructor. Just change the parameter type of TsmHeap<T>.Create to IComparer<T> and it should work.
Related
I have the following classes declared in a single file:
type
TCongruence = class(TObject)
private
a, b, n, numClass: integer;
solutions, vals: TSolutions;
hasSolutions: boolean;
function divides(a, b: integer): boolean;
function modulo(a, b: integer): integer;
public
constructor Create(a, b, n: integer); virtual;
function getSolutions: TSolutions; virtual;
function gcdExtended(p, q: integer): TSolutions;
class function getGCD(u, v: integer): integer;
property valA: integer read a;
property valB: integer read b;
property valN: integer read n;
property getClass: integer read numClass;
property hasSol: boolean read hasSolutions;
end;
type
TConguenceSystem = class(TCongruence)
private
system: array of TCongruence;
public
constructor Create(a: array of TCongruence); override;
function getSolutions: integer; override;
end;
The second one as you can see is a subclass because I need to use all the functions implemented in the TCongruence class. I have declared the constructor virtual so that I can call the override on the descendant.
Is that correct? Do I have to remove the virtual/override and simply use the constructor like this? (below)
constructor Create(a: array of TCongruence);
I guess that in this case I am hiding the father's constructor. I have declared this constructor:
constructor TConguenceSystem.Create(a: array of TCongruence);
var i: integer;
begin
SetLength(system, length(a)); // private var system: array of TCongruence
for i := Low(a) to High(a) do
begin
system[i] := a[i];
end;
solutions := false;
end;
When you intend to override behaviour of a method with the same signature in a descendent class then you must declare it virtual in the base class and the descendent class would then use override.
If, however, you wish to introduce a new method with a different signature then you must use the overload directive if you are declaring the method within the same class. This simply allows re-use of the same method name for what are, effectively, entirely different methods with different signatures. For example :
TCongruence = class(TObject)
public
constructor Create(a : integer); overload;
constructor Create(a, b, n: integer); overload;
end;
If you are declaring a new method in a descendent class, however, with a different signature then none of these decorations are required.
TCongruence = class(TObject)
public
constructor Create(a, b, n: integer);
end;
TCongruenceSystem = class(TCongruence)
public
constructor Create(a: array of TCongruence);
end;
The above is fine - you are not overriding the original constructor, you are simply introducing a new one with a new signature. Since the latter belongs to a new class with a different name there is no ambiguity and overload is not required. You can even access the ancestor methods in the usual way here :
TCongruence = class(TObject)
private
Fa, Fb, Fn : integer;
public
constructor Create(a, b, n: integer);
end;
TCongruenceSystem = class(TCongruence)
private
FArr : array of TCongruence;
public
constructor Create(a: array of TCongruence);
end;
constructor TCongruence.Create(a, b, n: integer);
begin
inherited Create;
Fa := a;
Fb := b;
Fn := n;
end;
constructor TCongruenceSystem.Create(a: array of TCongruence);
var
c : TCongruence;
i : integer;
begin
inherited Create(a[0].Fa, a[1].Fb, a[2].Fn);
SetLength(FArr, Length(a));
i := 0;
for c in a do begin
FArr[i] := c;
Inc(i);
end;
end;
Without the overload directive, however, the following would not be allowed :
var
cs : TCongruenceSystem;
begin
cs := TCongruenceSystem.Create(1, 2, 3);
end.
since TCongruenceSystem is hiding the base class Create which takes three integer arguments. If you allow the overload, however :
TCongruence = class(TObject)
private
Fa, Fb, Fn : integer;
public
constructor Create(a, b, n: integer); overload;
end;
TCongruenceSystem = class(TCongruence)
private
FArr : array of TCongruence;
public
constructor Create(a: array of TCongruence); overload;
end;
Then the above call of cs := TCongruenceSystem.Create(1, 2, 3); would be allowed and the ancestor constructor would be used to build the descendent class.
These approaches can be combined, for example :
TCongruence = class(TObject)
public
constructor Create(a : integer); overload; virtual; {overridable}
constructor Create(a, b, n: integer); overload; {only in base}
end;
TCongruenceSystem = class(TCongruence)
public
constructor Create(a:integer); overload; override; {overrides parent}
constructor Create(a: string); overload; {introduce new}
end;
In the case of the constructor you are introducing a method with a different set of parameters so this is allowed. In the case of getSolutions, however, the function is takes no parameters and differs only in the return type. An overloaded method needs to have a different parameter set, however, so this type of mutation is not allowed in a descendent class. getSolutions in the descendent class would need to take a different name if you intend it to also be a parameterless function with a different return type.
In Delphi 10 Berlin under Windows I have the following question regarding the freeing of generic lists:
I have the following record/list structure:
type
TMyRecord=record
Value1: Real;
SubList1: TList<Integer>;
SubList2: TList<Real>;
end;
TMyListOfRecords=TList<TMyRecord>;
I want to free the structure with the following code:
var
i: Integer;
AMyListOfRecords: TMyListOfRecords;
begin
//other code
//free AMyListOfRecords and all its content
for i:=0 to AMyListOfRecords.Count-1 do
begin
AMyListOfRecords[i].SubList1.Free;
AMyListOfRecords[i].SubList2.Free;
end;
AMyListOfRecords.Free;
end;
This seems to work. But I am wondering if there is a simpler or more elegant solution?
You could transform record type to class - overhead is negligible because record already contains sub-objects. Free sub-objects in this class destructor, and use
TMyListOfClasses = TObjectList<TMyClass>;
with OwnsObjects = True
In this case all you need is
AMyListOfClasses.Free;
You can define the interfaced list for the sub-items like:
type
TMyRecord=record
Value1: Real;
SubList1: IList<Integer>;
SubList2: IList<Real>;
end;
TMyListOfRecords=TList<TMyRecord>;
Where IList is kind of:
type
IList<T> = interface
function Add(const AValue: T): Integer;
function Remove(AValue: T): Integer;
end;
where you implement it like this:
TIntfList<T> = class(TInterfacedObject, IList<T>)
private
FList: TList<T>;
function Add(const AValue: T): Integer;
function Remove(AValue: T): Integer;
constructor Create;
destructor Destroy; override;
end;
{ TIntfList<T> }
function TIntfList<T>.Add(const AValue: T): Integer;
begin
Result := FList.Add(AValue);
end;
constructor TIntfList<T>.Create;
begin
FList := TList<T>.Create;
end;
destructor TIntfList<T>.Destroy;
begin
FList.Free;
inherited;
end;
function TIntfList<T>.Remove(AValue: T): Integer;
begin
Result := FList.Remove(AValue);
end;
After that you can assign fields of your record with TIntfList.Create and they will be released automatically with your records.
Important I am using Delphi XE 7
I am new to data snap, and I have setup a data snap server and client with the wizard in the menu along side a short tutorial from youtube
The server and client application works and communicates with each other. But in my server methods unit (The unit that contains all the functions that the client can call) I am trying to initialize the variables that I have created in the class (Setting some integers to 0 etc).
I have attempted to override the constructor create, but it would appear as though it is never being called.
I have marked it with virtual, override and overload but none of them seems to be executing this code:
constructor TServerMethods1.create(AOwner: TComponent);
begin
messagedlg('worked', mtError, [mbOk], 0);
inherited;
end;
I originally had the variables in there but it occurred to me that it wasn't executing.
Am I missing something or does it never execute, and if it never executes how does the client call the methods.
Edit - This is the class declaration:
type
tPlayer = record
PlayerName: String;
Spot: Integer;
end;
{$METHODINFO ON}
TServerMethods1 = class(TComponent)
TmrGameStarted: TTimer;
private
{ Private declarations }
fSpot1Taken: Boolean;
fSpot2Taken: Boolean;
fSpot3Taken: Boolean;
fSpot4Taken: Boolean;
fSpot5Taken: Boolean;
Player: Array [1 .. 5] of tPlayer;
fGameStarted: Boolean;
public
{ Public declarations }
fPlayerCount: Integer;
constructor create(AOwner: TComponent); overload;
function getPlayerCount: Integer;
procedure setPlayerCount(i: Integer);
function EchoString(Value: string): string;
function ReverseString(Value: string): string;
function Attempt_Join(sPlayerName: String; sPassword: String): String;
function UpdateLog: String;
function GameStarted: String;
end;
{$METHODINFO OFF}
I have also included the following in my constructor:
constructor TServerMethods1.create(AOwner: TComponent);
begin
messagedlg('worked', mtError, [mbOk], 0);
inherited create(AOwner);
end;
This is the constructor method from System.Classes which is a public declaration constructor Create(AOwner: TComponent); virtual;
{ TComponent }
constructor TComponent.Create(AOwner: TComponent);
begin
FComponentStyle := [csInheritable];
if AOwner <> nil then AOwner.InsertComponent(Self);
end;
This is also added in the type declaration but I have no idea what it does
private class var
FComparer: IComparer<TComponent>;
class constructor Create;
Constructor method:
class constructor TComponent.Create;
begin
FComparer := TDelegatedComparer<TComponent>.Create(
function(const Item1, Item2: TComponent): Integer
begin
Result := CompareText(Item1.Name, Item2.Name);
end);
end;
Okay. I have found the answer to my question. The on create even fires but it fires each time the client calls the function.
After doing some more research it would appear as there isn't an actual way to manipulate the server methods from a form or an application.
Datasnap could be useful depending on what you need it for, In my case I used it in the incorrect way. To use the create constructor just add the override directive. This will override the default parent constructor and execute yours.
In Delphi, IUnknown is declared as:
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
Note: The output parameter is untyped
In my TInterfacedObject descendant i need to handle QueryInterface, so i can return an object that supports the requested interface:
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if IsEqualGUID(IID, IFooBar) then
begin
Obj := (TFooBar.Create(Self) as IFooBar);
Result := S_OK;
end
else
Result := inherited QueryInterface(IID, {out}Obj);
end;
The problem comes on the line:
Obj := (TFooBar.Create(Self) as IFooBar);
Delphi complains:
Operator not applicable to this operand type
Obviously i don't know how or what to assign to an untyped out parameter. i can randomly try things, in hopes that the compiler will stop complaining:
Obj := TFooBar.Create(Self);
Obj := Pointer(TFooBar.Create(Self));
Obj := Pointer(TFooBar.Create(Self) as IFooBar);
Ignoring all the code i've written (if required): how do i implement QueryInterface in an object descendant from TInterfacedObject?
The real problem i've been trying to solve can be boiled down to i want to:
i want to override methods in an interface
In the same way:
TList = class(TObject)
...
function GetItem(Index: Integer): Pointer;
procedure SetItem(Index: Integer; Value: Pointer);
property Items[Index: Integer]: Pointer read GetItem write SetItem;
end;
can be overridden in a descendant class:
TStudentList = class(TList)
...
function GetItem(Index: Integer): TStudent;
procedure SetItem(Index: Integer; Value: TStudent);
property Items[Index: Integer]: TStudent read GetItem write SetItem;
end;
i want to so the same with interfaces:
IFoo = interface(IUnknown)
...
function GetItem(Index: Variant): Variant;
procedure SetItem(Index: Variant; Value: Variant);
property Items[Index: Variant]: Variant read GetItem write SetItem;
end;
IFooGuidString = interface(IFoo)
...
function GetItem(Index: TGUID): string ;
procedure SetItem(Index: TGUID; Value: string );
property Items[Index: TGUID]: string read GetItem write SetItem;
end;
Problem is that how i have to begin loading up my implementing object with:
TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
function IFoo.GetItem = FooGetItem;
procedure IFoo.SetItem = FooSetItem;
function FooGetItem(Index: Variant): Variant;
procedure FooSetItem(Index: Variant; Value: Variant);
function IFooGuidString.GetItem = FooGuidStringGetItem;
procedure IFooGuidString.SetItem = FooGuidStringSetItem;
function FooGuidStringGetItem(Index: TGUID): string ;
procedure FooGuidStringSetItem(Index: TGUID; Value: string );
end;
And there isn't just the two methods in IFoo, there's 6. And then if i want to add another supported interface:
IFooInt64String = interface(IFoo)
...
function GetItem(Index: Int64): string ;
procedure SetItem(Index: Int64; Value: string );
property Items[Index: Int64]: string read GetItem write SetItem;
end;
TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
function IFoo.GetItem = FooGetItem;
procedure IFoo.SetItem = FooSetItem;
function FooGetItem(Index: Variant): Variant;
procedure FooSetItem(Index: Variant; Value: Variant);
function IFooGuidString.GetItem = FooGuidStringGetItem;
procedure IFooGuidString.SetItem = FooGuidStringSetItem;
function FooGuidStringGetItem(Index: TGUID): string ;
procedure FooGuidStringSetItem(Index: TGUID; Value: string );
function IFooInt64String.GetItem = FooInt64StringGetItem;
procedure IFooInt64String.SetItem = FooInt64StringSetItem;
function FooInt64StringGetItem(Index: Int64): string ;
procedure FooInt64StringSetItem(Index: Int64; Value: string );
end;
And things get really unwieldy very fast.
You need to type-cast the left side of the assignment statement. That way, the untyped parameter has a type, and the compiler knows how to assign it a value:
IFooBar(Obj) := TFooBar.Create(Self) as IFooBar;
Please note that you're breaking one of the requirements of COM. If you query for an interface, you should be able to query the result for IUnknown and always get the same value:
Foo.QueryInterface(IUnknown, I1);
I1.QueryInterface(IFooBar, B);
B.QueryInterface(IUnknown, I2);
Assert(I1 = I2);
If you just want to generate new objects of type TFooBar, then give your interface a method that generates those:
function TFoo.NewFooBar: IFooBar;
begin
Result := TFooBar.Create(Self) as IFooBar;
end;
Besides of Rob's remarks of breaking the rules here, you can even succeed with this construct:
function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if IsEqualGUID(IID, IFooBar) then
Result := TFooBar.Create(Self).QueryInterface(IID, obj)
else
Result := inherited QueryInterface(IID, {out}Obj);
end;
I didn't investigate this, but you might get some problems with reference counting...
Based on the implementation of TObject.GetInterface in System.pas I would suggest this:
Pointer(Obj) := TFooBar.Create(Self);
I have a class TChild derived from TParent. TParent has a property MyProp that is reading and setting some values in an array. Of course this property is inherited by the TChild, but I want to add few extra processing in child's property. The code below explains better what I want to do but it is not working. How can I implement it?
TParent = class...
private
function getStuff(index: integer): integer; virtual;
procedure setStuff(index: integer; value: integer); virtual;
public
property MyProp[index: integer] read GetStuff write SetStuff
end;
TChild = class...
private
procedure setStuff(index: integer; value: integer); override;
function getStuff(index: integer): integer; override;
public
property MyProp[index: integer] read GetStuff write SetStuff
end;
procedure TChild.setStuff(value: integer);
begin
inherited; // <-- execute parent 's code and
DoMoreStuff; // <-- do some extra suff
end;
function TChild.getStuff;
begin
result:= inherited; <---- problem was here
end;
Solved.
The child function implementation was wrong. Basically that code works.
The solution was:
Result := inherited getStuff(Index);