Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Funktionen durchschleifen


tacl - Fr 16.07.10 09:33
Titel: Funktionen durchschleifen
Hi Leute,

ich glaub ich steh grad nur kräftig auf'm Schlauch und hoffe, dass mir jemand helfen kann.

Innerhalb einer Klasse definiere ich ein Feld, dass ich von klasseneigenen Methoden bearbeiten lassen möchte.
Eine Bearbeitung von ausserhalb der Instanz möchte ich verhindern. Jedoch soll das Feld möglichst ohne den Umweg über eine Methode ausgelesen werden können.
Die Symbole private und protected sind ja ungeeignet, da der Lesezugriff ja auch gesperrt wird.

Hat jemand die Lösung für mich?

Danke und Gruß
Patrick


Hidden - Fr 16.07.10 09:39

hi :)

Vielleicht kannst du den Zugriff über eine property gestalten:

Delphi-Quelltext
1:
2:
3:
4:
private
  FMyField: TMyField;
public
  property rOnly: TMyField read FMyField {write FMyField};


Propertys sind auch deshalb praktisch, weil man so später sehr einfach das Auslesen beispielsweise doch noch durch eine Funktion filtern lassen kann: Einfach read FMyField durch den Namen einer Funktion mit Rückgabewert TMyField ersetzen(sollte private/protected deklariert sein).
Hätte man die Funktion als public deklariert, müsste man für eine spätere Änderung des Aufrufs jeden einzelnen Aufruf getrennt umschreiben - von a := xyz auf P(xyz).

lg,


Narses - Fr 16.07.10 09:49

Moin!

Ich denke, das ist nicht das, was er möchte. Vermutlich geht es um den Inhalt des Feldes, der soll read-only sein. AFAIK geht das nicht, wenn du das Feld rausreichst (und nicht nur ein Element per Index/Methode), dann geht immer beides, Lesen und Schreiben. :nixweiss:

cu
Narses


Hidden - Fr 16.07.10 10:07

Wenn es sich bei dem Feld um ein Array oder einen ähnlichen, auf Pointern basierenden Typ geht, hast du recht, user profile iconNarses. Da muss dann eine Funktion mit Argument her(Index übergeben). Die kann aber auch über eine Property gekapselt werden, und der Aufruf erfolgt wie bei Arrays.

Einfach gestrickte Prozeduren und Funktionen dürften vom Compiler aber inline umgesetzt werden, d.h. du bekommst unter Umständen sogar den selben Assembler-Code wie bei direktem Zugriff auf das Array oder hast zumindest kein push und call drin.

Ich habe user profile icontacl jetzt aber so verstanden, dass es sich bei dem Feld um eine Feldvariable handelt, also eine wie oben gezeigt in der Klasse deklarierten. Das ist dann genau der Anwendungsfall für Propertys.

lg,


tacl - Fr 16.07.10 10:41

Hallo zusammen,

vielen Dank für Eure Antworten!

Der Weg über eine Property ist wie für mich gemacht, da der Weg der Befüllung über einen gekoppelten Funktionsaufruf


Delphi-Quelltext
1:
property StrVersion: String read GetVersion;                    


für mich absolut elegant ist. Die erste Lösung über ein Feld sah so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
type
  TConfig = class(TObject)
    StrVersion: String;
   private
    function GetVersion:String;
  public
    constructor Create;
  end;


Die Befüllung hätte dann für alle Felder im Constructor erfolgen müssen.
Da der Zugriff auf eine Property genauso erfolgt wie auf ein Feld, muss ich im vorgelagerten Quelltext nicht einmal etwas ändern.

Vielen Dank!!

Patrick


Narses - Fr 16.07.10 11:14

Moin!

OK, ich hab´s falsch verstanden, es ging also doch nicht um ein "Feld" (=array). :idea: ;)

cu
Narses


tacl - Fr 16.07.10 11:20

Hi!

Nein, in diesem Fall ging es nicht um ein Array. Vor einem ähnlichen Problem werde ich wohl nächste Woche stehen,
wenn ich mich an den Errorhandler für mein Projekt begebe. :roll:


jaenicke - Sa 24.07.10 09:50

Es gibt auch so etwas:

Delphi-Quelltext
1:
2:
3:
4:
private
  function GetData(Index: Integer): string;
property
  Data[Index]: string read GetData;
Zudem kannst du, wenn du eine Klasse zurücklieferst, innerhalb dieser Klasse wiederum den Zugriff sperren. Dort gibt es die Möglichkeit über Interfaces private und protected Methoden nach außen sichtbar zu machen. Wenn man dann über die normale Klasse von außen zugreift, kommt man nicht heran, wenn man über das Interface zugreift schon.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
type
  ITestClassFullAccess = interface
    procedure SetTest(const Value: string);
  end;

  TTestClass = class(TInterfacedObject, ITestClassFullAccess)
  private
    FTest: string;
  protected
    procedure SetTest(const Value: string);
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    property Test: string read FTest;
  end;


implementation

{ TTestClass }

function TTestClass.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

function TTestClass._AddRef: Integer;
begin
  Result := 1// no reference counting neccessary
end;

function TTestClass._Release: Integer;
begin
  Result := 1// no reference counting neccessary
end;

procedure TTestClass.SetTest(const Value: string);
begin
  FTest := Value;
end;
Das Interface kannst du auch in eine andere Unit packen, damit man diese einbinden muss um Schreibzugriff zu bekommen. Jedenfalls kannst du dann das machen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
var
  a: TTestClass;
begin
  a := TTestClass.Create();
  try
    ITestClassFullAccess(a).SetTest('aaa');
    ShowMessage(a.Test);
  finally
    a.Free();
  end;
Ohne das Interface kommst du nur lesend an die Klasse heran.