Visibility & Properties

Members declared before any specifier are published if the class is compiled with {$M+} (or descends from TPersistent), otherwise public.

25.1 Visibility specifiers

the class and all code in the same unit strict private the class only the class, descendants, and code in the same unit strict protected the class and descendants only everyone + RTTI generated (Object Inspector, streaming to .lfm/.dfm) legacy COM automation (obsolete)

Members declared before any specifier are published if the class is compiled with {$M+} (or descends from TPersistent), otherwise public. Use strict private for real encapsulation.

25.2 Properties

A property looks like a field to callers but can map to a field or to getter/setter methods:

property Name: string read FName write FName; property Count: Integer read GetCount write SetCount; property Id: Integer read FId; Write-only (rare)

property Password: string write SetPassword; Indexed (shared accessor)

property Left: Integer index 0 read GetCoord write SetCoord;

property Items[Index: Integer]: string read GetItem write SetItem; default; Default value (streaming)

property Visible: Boolean read FVisible write FVisible default True;

property Caption: string read FCaption write FCaption stored IsCaptionStored;

class property Count: Integer read FCount;

type
  TTemperature = class
  private
    FCelsius: Double;
    function GetFahrenheit: Double;
    function GetKelvin: Double;
    procedure SetFahrenheit(AValue: Double);
    procedure SetCelsius(AValue: Double);
  public
    property Celsius: Double read FCelsius write SetCelsius;
    property Fahrenheit: Double read GetFahrenheit write SetFahrenheit;
    property Kelvin: Double read GetKelvin;        // read-only
  end;

function TTemperature.GetKelvin: Double;
begin
  Result := FCelsius + 273.15;
end;

procedure TTemperature.SetCelsius(AValue: Double);
begin
  if AValue < -273.15 then
    raise ERangeError.Create('Below absolute zero');
  FCelsius := AValue;
end;

function TTemperature.GetFahrenheit: Double;
begin
  Result := FCelsius * 9 / 5 + 32;
end;

procedure TTemperature.SetFahrenheit(AValue: Double);
begin
  Celsius := (AValue - 32) * 5 / 9;    // reuse validation
end;

25.3 Array properties and default

type
  TMatrix = class
  private
    FData: array of Double;
    FRows, FCols: Integer;
    function GetCell(R, C: Integer): Double;
    procedure SetCell(R, C: Integer; AValue: Double);
  public
    constructor Create(ARows, ACols: Integer);
    property Cells[R, C: Integer]: Double read GetCell write SetCell; default;
    property Rows: Integer read FRows;
    property Cols: Integer read FCols;
  end;

constructor TMatrix.Create(ARows, ACols: Integer);
begin
  inherited Create;
  FRows := ARows;
  FCols := ACols;
  SetLength(FData, ARows * ACols);
end;

function TMatrix.GetCell(R, C: Integer): Double;
begin
  Result := FData[R * FCols + C];
end;

procedure TMatrix.SetCell(R, C: Integer; AValue: Double);
begin
  FData[R * FCols + C] := AValue;
end;

// usage: M[1, 2] := 3.5;  — same as M.Cells[1, 2] := 3.5

25.4 Events are properties too

A form assigns a handler: Downloader.OnDone := @DownloadFinished; (objfpc) or Downloader.OnDone := DownloadFinished; (Delphi). This "method pointer" mechanism is the foundation of the LCL/VCL event model.

type
  TNotifyEvent = procedure(Sender: TObject) of object;   // already declared in Classes

  TDownloader = class
  private
    FOnDone: TNotifyEvent;
  public
    procedure Run;
    property OnDone: TNotifyEvent read FOnDone write FOnDone;
  end;

procedure TDownloader.Run;
begin
  // ... work ...
  if Assigned(FOnDone) then
    FOnDone(Self);           // fire the event
end;