I am creating a class with class constructor
TStaticDynSettings = class
public
class constructor create;
class destructor destroy;
class procedure Reload;
end;
Do all the other method in the class apart from create and destroy need to be a class methods?
I know for sure all the variables need to be a class var else the automatic initialization wont work.
what is the difference in calling the procedure as?..
var StDyn : TStaticDynSettings;`
StDyn.Reload;
and
TStaticDynSettings.Reload;
1 - If you are not planning to create object instances of TStaticDynSettings you can use any of 3 forms:
type
TStaticDynSettings = class
public
procedure Reload1;
class procedure Reload2;
class procedure Reload3; static;
end;
call examples:
procedure Call1;
var Instance: TStaticDynSettings;
begin
Instance.Reload1;
end;
procedure Call2;
begin
TStaticDynSettings.Reload2;
end;
procedure Call3;
begin
TStaticDynSettings.Reload3;
end;
The difference is a hidden argument passed in Reload1 and Reload2 methods and not passed in Reload3.
The hidden argument is a reference to object instance in Reload1 (and not used since you are not creating object instance), and a class reference in Reload2 (which probably also unnecessary in your case, assuming a class reference is known at compile time).
The first form (Reload1) is misleading because it assumes using an object reference and so should be avoided (though it works).
The third form (Reload3) is preferable if you are not using class references that are unknown at compile time.
2 - There is no difference (not counting an overhead of using unnecessary object variable if the first case).
Related
I have to develop a game in Lazarus for school, and I ran into an error that I can't find a solution for.
I have a dynamic array where I want to store classes in so that I can call procedures on those classes.
TKarte is the ancestor class, and I have many different classes (all representing different Cards) that have the same procedures as the ancestor class.
unit Karten;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, Dialogs, ExtCtrls;
type
TKarte=class
public
class procedure GetPicture(Objekt:TImage);virtual;
class procedure OnPlay;virtual;
end;
type
Karte = class(TKarte)
public
class procedure GetPicture(Objekt:TImage);override;
class procedure OnPlay;override;
end;
type
Karte2 = class(TKarte)
public
class procedure GetPicture(Objekt:TImage);override;
class procedure OnPlay;override;
end;
implementation
class procedure Karte.OnPlay();
begin
ShowMessage(ClassName);
end;
class procedure Karte.GetPicture(Objekt:Timage);
begin
Objekt.Picture.LoadFromFile('Grafiken\Karten\Mindcontrol.png');
end;
class procedure Karte2.GetPicture(Objekt:Timage);
begin
Objekt.Picture.LoadFromFile('Grafiken\Karten\Mindcontrol.png');
end;
class procedure Karte2.OnPlay();
begin
ShowMessage(Karte2.ClassName);
end;
class procedure TKarte.OnPlay();
begin
ShowMessage(ClassName);
end;
class procedure TKarte.GetPicture(Objekt:TImage);
begin
Objekt.Picture.LoadFromFile('Grafiken\Sprites\Buttons\Button 1.png');
end;
end.
This is how I add them and call them from the array at the moment:
Hand: array of Class of TKarte;
procedure TSplashScreen.Button2Click(Sender: TObject);
begin
SetLength(Hand,Length(Hand)+1);
Hand[High(Hand)] := Karte;
Hand[High(Hand)].OnPlay();
Hand[High(Hand)].GetPicture(Image1);
end;
There is no problem with running the program, but when I try to add a new component, or I press CTRL + Space for the Auto-Complete, it gives me an error at the declaration of the array:
Error: Anonymous Class definitions are not allowed
I have tried to find an answer to this problem, but there seems to be noone with the same problem :(
Can somebody help me?
Offhand, I see nothing wrong with the code, and as you said the code does run correctly. It is only the IDE that is having a problem with it. As such, I would not suggest declaring the array's element type directly in the array's declaration. I would suggest declaring an alias for it before declaring the array, eg:
type
TKarte=class
...
end;
TKarteClass = Class of TKarte;
...
Hand: array of TKarteClass;
There are few problems in your code.
When creating array of some type you don't define the said type in the array itself but only tell which type needs to be used. So your array definition would be:
Hand: array of TKarte;
I also see that you have declared all your procedures as class procedure. There is a fundamental difference between class methods and ordinary methods. Most likely you won't need them to be declared as class methods based on what you are trying to achieve. While I could not find suitable Lazarus documentation on this topic you may refer to Delphi documentation on Class methods to get better understanding about their difference.
I have developed a class and I need my object to be able to hold the "history" of what happened during the lifetime of the program.
type
TPipelineSimulator = class
private
class var history: TStringList;
class constructor Create;
class destructor Destroy;
//other code
public
class property bitHistory: TStringList read history;
//other code
end;
And the simple implementation is:
class constructor TPipelineSimulator.Create;
begin
history := TStringList.Create;
end;
class destructor TPipelineSimulator.Destroy;
begin
history.Free;
end;
The class TPipelineSimulator has a normal procedure (not class procedure) that adds strings to the history variable; in this way I can fill my stringlist and access it with this code:
for k := 0 to a.history.Count-1 do
Memo1.Lines.Add(a.history.Strings[k]);
This is very useful because even if the object is created and then released (the usual Free inside try-finally) I still can access to the stringlist. I have two questions about class constructors and destructors.
The documentation says that constructors are inserted automatically by the compiler into the initialization section. The opposite happens with destructors. Does this mean that if I called var a: TPipelineSimulator; inside a button onclick procedure the class constructor for a is called when the program starts? Or just when I call the procedure for the first time?
In case of an exception (maybe by mistake I go out of bounds in the stringlist) do I risk a memory leak?
In point 2 I mean something like this. If the StringList is filled with 1 item each time, at the beginning the code below causes an out of bounds error a few times:
showmessage(a.history.strings[10]);
Despite that I can still access the stringlist and I has really wondering if this code is dangerous.
1) Class constructors are executed with the initialization section of the unit in which the class is implemented - to be precise: immediately before the code in the initialization section. For the destructor it is the other way round. The initialization order of the units is determined by the compiler.
The difference to the initialization/finalization section code is that class constructors/destructors are executed only if the class is actually used inside the program.
2) As long as the class destructor is called, you don't get a memory leak (at least not from this stringlist).
I saw a code like this the other day:
type
TcxGridTableControllerAccess = class (TcxGridTableController);
TMycxGridDBTableView = class (TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class (TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class (TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class (TMycxGridDBTableView);
TMycxGridDBTableView inherited from TcxGridDBTableView that inherited from TMycxGridDBTableView. Searched for Cyclic Inheritance but only Java results.
What is this called?
Ps: I don't have the full buildable code with me.
The example code doesn't do what you think it does. You see TMycxGridDBTableView being defined as a descendant of TcxGridDBTableView, and then you see TcxGridDBTableView, defined as a descendant of TcxGridDBTableView.
However, the TcxGridDBTableView you see at the top is not the same TcxGridDBTableView that you see later. The first one refers to a class declared elsewhere, in some other unit. The next occurrence is declaring a new class in this unit that happens to have the same base name as the other unit's class.
This technique is known as an interposer class. It's used to introduce a new GetViewDataClass method, but still end up with the same class name. The form that uses controls with that name will use the new version of the class instead of the original version. It's a way to customize a VCL control without having to compile and install a custom package.
What you show is not cyclic inheritance. What happens is that dxSample.TMycxGridDBTableView inherits from a TcxGridDBTableView in another unit, probably cxGridDBTableView.TcxGridDBTableView. And dxSample.TcxGridDBtableView inherits from dxSample.TMycxGridDBTableView.
Your code is equivalent to:
type
TcxGridTableControllerAccess = class(TcxGridTableController);
{ Note: this does NOT inherit from the TcxGridDBTableView defined }
{ a little further on in the source. It inherits from the original }
{ DevEx TcxGridDBTableView. }
TMycxGridDBTableView = class(cxGridDBTableView.TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class(TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class(TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class(TMycxGridDBTableView);
So the hierarchy is:
cxGridDBTableView.TcxGridDBTableView
|
v
dxSample.TMycxGridDBTableView
|
v
dxSample.TcxGridDBTableView
So dxSample.TMycxGrdiDBTableView does not inherit from dxSample.TcxGridDBTableView, but from cxGridDBTableView.TcxGridDBTableView instead, so there is no so called cyclic inheritance there. The whole misunderstanding comes from the fact that the two classes in the different units have the same name and that the first declaration does not fully qualify the class it is inheriting from.
Now, if someone puts the unit dxSample after cxridDBTableView in his or her uses clause, then dxSample.TCxGridDBTableView is used, instead of the original DevEx class. This is called interposing.
When people want to modify the behaviour of the VCL and FireMonkey, it is not unusual to see interposer classes like
type
TVCLClass = class(OriginalVCLUnit.TVCLClass)
// modifications to the original TVCLClass
end;
or
type
TMyVCLClass = class(OriginalVCLUnit.TVCLClass)
//
end;
TVCLClass = class(TMyVCLCLass);
The code you showed does the latter.
I'm wanting to implement some logging functions in a class I have here. Basically, my thought is to create a TStringList within the class which contains the log. I can do this without any trouble, but my question is how to expose it outside of the class in a way that a control (TMemo or TListBox) can dynamically show the contents if the containing form is present. I could make a direct association to the control within the class, but I'm wanting to keep the class discreet from the form code itself, and create a procedure in the class which makes this association.
Basically, if I have LogFile: TStringList in my class, how do I make it so adding a line there makes it show up in a TMemo from a form that is separate from the class?
Let the form register a callback event in your class.
If this event is assigned when adding an item to your list, use the callback to send the string.
Type
TMyCallback = procedure(const aLogStr: String) of object;
TMyClass = Class
private
FCallback : TMyCallback;
FLogFile : TStringList;
procedure SetCallback(ACallback: TMyCallback);
public
property Callback : TMyCallback write SetCallback;
end;
...
// Update FLogFile
FLogFile.Items.Add(SomeText);
if Assigned(FCallback) then
FCallBack(SomeText);
...
In your form class:
Type
TMyForm = Class(TForm)
private
procedure IncomingLogString(const AStr: String);
end;
procedure TMyForm.IncomingLogString(const AStr: String);
begin
MyMemo.Lines.Add(AStr);
end;
...
// Register callback
FMyClass.Callback := Self.IncomingLogString;
Now, your TMyClass is decoupled from any dependence from the form.
I have a persistence framework, and I am trying to use generics so I don't have to keep creating new list classes for each type of object I want to store in a type safe way.
I have a method that returns the class of the contained object in the list class (so I know which queries to run and which object to create.
As an example, it looks something like this:
type
TMyObject = class
end;
TMyObjectClass = class of TMyObject;
TMyObjectList = class
public
function ListClass: TMyObjectClass; virtual; abstract;
end;
TMyObjectList<T: TMyObject, constructor> = class(TMyObjectList)
public
function ListClass: TMyObjectClass; override;
end;
implementation
{ TMyObjectList<T> }
function TMyObjectList<T>.ListClass: TMyObjectClass;
begin
result := T; // <==== this wont compile
end;
end.
Is there a way of returning the class of the generic parameter in this case?
Thanks
N#
(using Delphi 2009)
This is a known issue in Delphi 2009. It's been fixed in 2010. I just tested it and your code compiles just fine there.
T is not an instance of an object.
In your specific example, you should write something like:
result := self;
I think you're looking the wrong way...