Lazarus

Free Pascal => General => Topic started by: MarkMLl on September 18, 2021, 09:52:17 pm

Title: [Solved] Class variables
Post by: MarkMLl on September 18, 2021, 09:52:17 pm
If a class has a field which is itself (an instance of) a class, where should that be instantiated?

I have a class TStation, where instances are usually accessed via a name/object stringlist. It occurs to me that the stringlist, together with a TCriticalSection protecting addition/deletion/reference operations, could usefully be a class variable... but that leaves me with a bootstrapping problem since until the stringlist and critical section exist I can't do anything useful.

MarkMLl
Title: Re: Class variables
Post by: ASerge on September 19, 2021, 06:35:28 am
If a class has a field which is itself (an instance of) a class, where should that be instantiated?
General fields - in constructor/destructor. Class fields - in class constructor/destructor.
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}
  2. {$LONGSTRINGS ON}
  3. {$APPTYPE CONSOLE}
  4.  
  5. uses SysUtils, Classes;
  6.  
  7. type
  8.   TClassWithClassField = class(TObject)
  9.   strict private
  10.     class var FClassVar: TStringList;
  11.     var FGeneralVar: TStringList;
  12.   public
  13.     class constructor Create;
  14.     class destructor Destroy;
  15.     constructor Create;
  16.     destructor Destroy; override;
  17.     property GeneralVar: TStringList read FGeneralVar;
  18.     class property ClassVar: TStringList read FClassVar;
  19.   end;
  20.  
  21. class constructor TClassWithClassField.Create;
  22. begin
  23.   FClassVar := TStringList.Create;
  24.   FClassVar.Append('Class var');
  25.   Writeln('class constructor');
  26. end;
  27.  
  28. class destructor TClassWithClassField.Destroy;
  29. begin
  30.   FClassVar.Free;
  31.   Writeln('class destructor');
  32. end;
  33.  
  34. constructor TClassWithClassField.Create;
  35. begin
  36.   FGeneralVar := TStringList.Create;
  37.   FGeneralVar.Append(Format('General var Self=%p', [Pointer(Self)]));
  38.   Writeln('constructor');
  39. end;
  40.  
  41. destructor TClassWithClassField.Destroy;
  42. begin
  43.   FGeneralVar.Create;
  44.   Writeln('destructor');
  45. end;
  46.  
  47. procedure Test;
  48. var
  49.   C1, C2: TClassWithClassField;
  50. begin
  51.   Writeln('--Start');
  52.   C1 := TClassWithClassField.Create;
  53.   try
  54.     C2 := TClassWithClassField.Create;
  55.     try
  56.       Write(C1.ClassVar.Text);
  57.       Write(C1.GeneralVar.Text);
  58.       Write(C2.ClassVar.Text);
  59.       Write(C2.GeneralVar.Text);
  60.     finally
  61.       C2.Free;
  62.     end;
  63.   finally
  64.     C1.Free;
  65.   end;
  66.   Writeln('--End');
  67. end;
  68.  
  69. begin
  70.   Test;
  71.   Readln;
  72. end.
Title: Re: Class variables
Post by: MarkMLl on September 19, 2021, 09:08:31 am
Thanks for that, I admit that I'd overlooked the "class constructor" syntax (and am unsure where it's documented).

However experimenting... the class constructor appears to be being called implicitly before the unit startup, so is of no help when it comes to setting up a list of stations with an internal critical section where the station list can be created/destroyed as part of a thread. So it looks as though I have to have a separate TStationList as the container, and that in this particular case class variables etc. aren't much help.

MarkMLl
Title: Re: Class variables
Post by: ASerge on September 19, 2021, 09:14:12 am
... the class constructor appears to be being called implicitly before the unit startup
Yes, as documented (https://www.freepascal.org/docs-html/current/ref/refsu29.html#x82-1060006.6.5).
Title: Re: Class variables
Post by: MarkMLl on September 19, 2021, 10:06:42 am
... the class constructor appears to be being called implicitly before the unit startup
Yes, as documented (https://www.freepascal.org/docs-html/current/ref/refsu29.html#x82-1060006.6.5).

Thanks for that, I was looking in the wrong place.

MarkMLl
TinyPortal © 2005-2018