Schritt für Schritt zur klassenbasierten Programmierung - Teil 6

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Schritt für Schritt zur klassenbasierten Programmierung - Teil 6

Beitrag von fliegermichl »

Anmerkung: Auf mehrfache Anregung hin, werde ich diese Artikel demnächst in das Lazarus Wiki verlagern und hier dann nur einen Link darauf setzen.
Im vorigen Artikel hatte ich beschrieben, daß man mittels Properties einen kontrollierten Zugriff auf die Felder einer Klasse hat bzw "virtuelle" Properties (Durchmesser) definieren kann, welche mittels der Setter- und Gettermethoden durch Umrechnungen funktionieren.

Da gibt es aber ein Problem.
Nichts kann einen daran hindern, trotzdem unkontrolliert schreibend auf die Felder der Klasse zuzugreifen und die ganze Mühe mit den Settermethoden und den Properties wäre umsonst.

Dafür haben sich die Compilerentwickler die sogenannte Sichtbarkeit von Feldern, Methoden und Properties ausgedacht.
Felder, Methoden sowie Properties können für externen Code sowie auch für Nachfahren einer Klasse unsichtbar gemacht werden.
Dafür gibt es die Bezeichner private, protected, public sowie published.
Diese werden bei der Definition der Klasse angegeben und regeln, welcher Code auf welche Felder, Methoden oder Properties zugreifen kann.

Code: Alles auswählen

type
 TGeo = class
 strict private
  fBezeichnung : string;
  procedure SetBezeichnung(const Value : string);
 protected
  fX : integer;
  fY : integer;
  procedure SetX(const Value : integer);
  procedure SetY(const Value : integer);
  property Y : integer read fY write SetY;
 public
  property Bezeichnung : string read fBezeichnung write SetBezeichnung;
  property X : integer read fX write SetX;
 end;
Die obige Definition legt fest, daß nur Methoden von TGeo Zugriff auf das Feld fBezeichnung und die Methode SetBezeichnung haben.
Von TGeo abgeleitete Klassen (TRechteck etc.) sowie alle weiteren Nachfahren haben Zugriff auf die unter protected definierten Felder, Methoden und Properies.
Alle unter public aufgeführten Felder, Methoden und Properies können von jedem externen Code verwendet werden.

Allerdings kann der Programmierer von Nachfahrenklassen diese Sichtbarkeit erhöhen (jedoch nicht verringern).
Dazu wird der entsprechende Bezeichner mit einer erhöhten Sichtbarbeit erneut definiert.

So hat externer Code im obigen Beispiel keine Möglichkeit auf die Y Position zuzugreifen (weder lesend noch schreibend).
Wenn der Programmierer von z.B. TRechteck aber möchte, daß man auch die Y Position von externem Code aus beeinflussen kann, so kann er dies bei der Definition von TRechteck angeben.

Code: Alles auswählen

type
 TRechteck = class ( TGeo )
 public
  property Y;  // muss nur erneut aufgeführt werden
  ...
 end;
Für Felder, Methoden und Properties, die die Sichtbarkeit published haben, wird zusätzlicher Code erzeugt (RTTI), der diese Informationen auch zur Laufzeit des Programmes zur Verfügung stellt. Dies wird im wesentlichen durch die Lazarus IDE für die Bearbeitung der Komponenteneigenschaften im Objektinspektor benötigt.

Der Zusatz strict legt fest, daß private auch für Klassen aus der gleichen Unit gilt. Ohne diesen Zusatz können Klassen aus der gleichen Pascalunit auch auf private Felder und Methoden anderer Klassen zugreifen.

Wird keine Angabe zur Sichtbarkeit gemacht, so gilt public.

Man kann die Sichtbarkeiten auch mehrfach definieren (also das z.B. nach einer Reihe von ,mit public definierten Feldern, Methoden und Properties erneut welche mit der Sichtbarkeit private folgen können.)

Damit lassen sich logisch zusammenhängende Felder, Methoden und Properties mit ihren Sichtbarkeiten sinnvoll gruppieren.

Innerhalb einer Sichtbarkeit müssen immer zuerst alle Felder, dann alle Methoden und zum Schluss die Properties definiert werden.

Da ich außer fModified für die Zukunft noch mehr boolsche Properties geplant habe, habe ich die nicht in eigene boolsche Felder getan, sondern verwende ein Set.
Die Setter- und Getter Methoden der boolschen Properties verwenden dieses Set dann.

Code: Alles auswählen

type
 TGeoFlag = (gfModified, gfVisible, gfReadOnly, gfSelected usw.)
 TGeoFlags = set of TGeoFlag;
 
 TGeo = class
 strict private
  fFlags : TGeoFlags;
  function GetModified : boolean;
  procedure SetModified(const Value : boolean);
  ...
 public
  property Modified : boolean read GetModified write SetModified;
  ...
 end;
  
implementation

function TGeo.GetModified: boolean;
begin
  Result := gfModified in fFlags;
end;

procedure TGeo.SetModified(const Value: boolean);
begin
  if Modified = Value then exit;
  if Value then
    Include(fFlags , gfModified)
  else
    Exclude(fFlags, gfModified);
end;

Genauso werden die weiteren boolschen Properties definiert.

Bis hierher war das ganz schön viel graue (oder vielleicht doch etwas erhellende?) Theorie.
Deshalb hab ich ein kleines Demoprojekt erstellt, welches die beschriebenen Klassen erzeugt und anzeigt.
Dateianhänge
geo.zip
Beispielprojekt für Artikel zur Klassenbasierten Programmierung (Teil 6)
(141.71 KiB) 77-mal heruntergeladen

Antworten