Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Constructor verbergen (https://www.delphipraxis.net/107583-constructor-verbergen.html)

s-off 30. Jan 2008 08:30


Constructor verbergen
 
Hallo zusammen,

folgende Ausgangssituation:

Gegeben sind die folgenden Klassen (abgespeckte Darstellung):
Delphi-Quellcode:
TMeinMemoObject = Class(TObject)
private
  FValue: String;
public
  Constructor Create(oMemo: TMeinMemo);

  Property Value: String read FValue;
end;

TMeinMemo = Class(TMemo)
private
  Function GetMeinMemoObject: TMeinMemoObject;
public
  Property MeinMemoObject : TMeinMemoObject read GetMeinMemoObject;
end;
Objekte der Klasse 'TMeinMemo' können direkt Objekte vom Typ 'TMeinMemoObject' erzeugen.
Zugriff erfolgt dann über die entsprechende Property, bspw.
Delphi-Quellcode:
sMeinString := oMeinMemo.MeinMemoObject.Value;
So, wie ich nun aber auf das Feld 'Value' zugreifen kann, wäre es genauso möglich, auf den Constructor zuzugreifen:
Delphi-Quellcode:
oMeinMemo.MeinMemoObject.Create(oMeinMemo);
Und genau das möchte ich verhindern.
Im Klartext: ich möchte verhindern, dass ein Objekt der Klasse 'TMeinMemoObject' von außen erzeugt werden kann.

Nun dachte ich, dass es genügen würde, den Constructor aus dem Public- einfach in den Private-Bereich zu packen.
Leider genügt das nicht, da so ja immer noch der Constructor von der Vorfahrklasse 'TObject' aufrufbar ist.

Meine Frage nun: Wie kann ich jeglichen Zugriff auf den Constructor von 'TMeinMemoObject' von außen verhindern, und diesen nur der Klasse 'TMeinMemo' ermöglichen?

RavenIV 30. Jan 2008 08:48

Re: Constructor verbergen
 
Also ich würde versuchen, den Constructor von TObject zu überschreiben und dann aus public rausnehmen.
Kann sein, dass Du dann eine Warning bekommst, aber auch das kann man bestimmt irgendwie "reparieren".
Ausnahmsweise kann man die Warning auch ignorieren.

TBx 30. Jan 2008 08:53

Re: Constructor verbergen
 
Den Constructor kannst Du über strict private sperren.
Diesen kannst Du dann über eine private Function Aufrufen. Diese private Function ist von Klassen aus, die in der selben Unit definiert sind, aufrufbar.

Das Prinzip kannst Du Dir angucken, wenn Du mal nach Singleton suchst, da wird auch der Constructor gesperrt.

Gruß

onlinekater

xaromz 30. Jan 2008 09:21

Re: Constructor verbergen
 
Hallo,
Zitat:

Zitat von RavenIV
Also ich würde versuchen, den Constructor von TObject zu überschreiben und dann aus public rausnehmen.

Du weisst aber schon, dass man Sichtbarkeit nur erhöhen kann, aber niemals vermindern, oder?

Delphi-Quellcode:
sMeinString := oMeinMemo.MeinMemoObject.Value;
Damit erzeugst Du IMHO kein neues Objekt, sondern rufst den Konstruktor eines bestehenden Objekts als normale Methode auf.

Gruß
xaromz

s-off 30. Jan 2008 09:31

Re: Constructor verbergen
 
Hallo,

vielen Dank für Eure Tipps.

Bezüglich der 'strict private'-Variante habe ich es nun auf zweierlei Art und Weise probiert:
Delphi-Quellcode:
TMeinMemoObject = Class(TObject)
strict private
  Constructor Create; overload;
private
  FValue: String;
 
  Procedure CreateMeinMemoObject(oMemo: TMeinMemo);
public
  Property Value: String read FValue;
end;

TMeinMemo = Class(TMemo)
private
  Function GetMeinMemoObject: TMeinMemoObject;
public
  Property MeinMemoObject : TMeinMemoObject read GetMeinMemoObject;
end;
Aufruf dann per
Delphi-Quellcode:
Procedure TMeinMemo.BaueMemoObject;
var
  oMemoObject: TMeinMemoObject;
Begin
  oMemoObject := TMeinMemoObject.CreateMeinMemoObject(Self);
End;
Diese Variante hat mehrere Compilermeldungen zur Folge:
Zitat:

[Pascal Fehler] uMeinMemo.pas(563): E2076 Diese Form des Methodenaufrufs ist nur für Klassenmethoden erlaubt
[Pascal Fehler] uMeinMemo.pas(731): E2075 Diese Form des Methodenaufrufs ist nur in Methoden von abgeleiteten Typen erlaubt
Die zweite Variante sieht so aus:
Delphi-Quellcode:
TMeinMemoObject = Class(TObject)
strict private
  Constructor Create; overload;
private
  FValue: String;
protected
  Constructor Create(oMemo: TMeinMemo); overload;
public
  Property Value: String read FValue;
end;

TMeinMemo = Class(TMemo)
private
  Function GetMeinMemoObject: TMeinMemoObject;
public
  Property MeinMemoObject : TMeinMemoObject read GetMeinMemoObject;
end;
Aufruf dann per
Delphi-Quellcode:
Procedure TMeinMemo.BaueMemoObject;
var
  oMemoObject: TMeinMemoObject;
Begin
  oMemoObject := TMeinMemoObject.Create(Self);
End;
Diese Variante hat nur einen Hinweis zur Folge, der nicht weiter stört
Zitat:

[Pascal Hinweis] uTSplitCellStringGrid.pas(96): H2219 Das private-Symbol 'Create' wurde deklariert, aber nie verwendet
Alles weitere Funktioniert so weit.
Wenn ich nun aber versuche, von außen auf den Constructor zuzugreifen, dann wird mir dieser auch nicht mehr in der CodeVervollständigung angezeigt, aufrufen kann ich ihn aber trotzdem, was dann zu einer Exception führt :cry:

Wo liegt der Fehler?

Edit:
@xaromz
Zitat:

Zitat von xaromz
Delphi-Quellcode:
sMeinString := oMeinMemo.MeinMemoObject.Value;
Damit erzeugst Du IMHO kein neues Objekt, sondern rufst den Konstruktor eines bestehenden Objekts als normale Methode auf.

damit möchte ich ja auch gar kein neues Objekt erzeugen, sondern nur Zeigen, wie ich auf Felder dieser Klasse von außen zugreife - das Beispiel mit dem Erzeugen des Objektes war etwas weiter unten
Zitat:

oMeinMemo.MeinMemoObject.Create(oMeinMemo);
;)

xaromz 30. Jan 2008 09:43

Re: Constructor verbergen
 
Hallo,

Zitat:

Zitat von s-off
@xaromz
Zitat:

Zitat von xaromz
Delphi-Quellcode:
sMeinString := oMeinMemo.MeinMemoObject.Value;
Damit erzeugst Du IMHO kein neues Objekt, sondern rufst den Konstruktor eines bestehenden Objekts als normale Methode auf.

damit möchte ich ja auch gar kein neues Objekt erzeugen, sondern nur Zeigen, wie ich auf Felder dieser Klasse von außen zugreife - das Beispiel mit dem Erzeugen des Objektes war etwas weiter unten
Zitat:

oMeinMemo.MeinMemoObject.Create(oMeinMemo);
;)

upps :oops: , falsche Stelle zitiert. Also nochmal:
Delphi-Quellcode:
oMeinMemo.MeinMemoObject.Create(oMeinMemo);
Damit erzeugst Du IMHO kein neues Objekt, sondern rufst den Konstruktor eines bestehenden Objekts als normale Methode auf.

Gruß
xaromz

uligerhardt 30. Jan 2008 09:44

Re: Constructor verbergen
 
Ich glaube nicht, dass das "sauber" geht. IMHO ist die beste Lösung (a.k.a das geringste Übel :-)), den "gewollten" Konstruktor privat zu machen sowie den unerwünschten geerbten zu überschreiben und als Implementierung eine Exception zu schmeißen. Damit kriegst du zwar leider keinen Compilerfehler bei unerlaubter Benutzung, aber immerhin einen deutlichen Hinweis zur Laufzeit. :mrgreen:

SirThornberry 30. Jan 2008 09:52

Re: Constructor verbergen
 
Selbst wenn du den Constructor verbergen kannst bringt dir das überhaupt nichts. Der Constructor ist nichts anderes als eine normale Methode die beim Aufruf als Klassen-Methode speicher anfordert. Wenn du dir aber zum Beispiel mit Application.CreateForm anschaust wirst du sehen das man nicht unbedingt den Constructor als Klassenmethode aufrufen muss um Speicher anzufordern.
Zudem kann man auch einfach immer auf einen Vorgänger casten wo der Constructor sichtbar ist und da den Constructor aufrufen.

Der Sinn ist also gleich null von dem was du vor hast. Und wenn du dir mal die Objecte der VCL anschaust wirst du auch nirgends sowas finden obwohl da genau das gleiche mit den Klassengemacht wird wie bei dir (ListView.Items.Add zum Beispiel).

s-off 30. Jan 2008 10:04

Re: Constructor verbergen
 
@xaromz:
Ups, bin schon ganz tüddelig :?
Meinte natürlich etwas wie
Delphi-Quellcode:
Procedure TForm1.TestClick(Sender: TObject);
Var
   oMeinMemoObject: TMeinMemoObject;
Begin
   oMeinMemoObject := TMeinMemoObject.Create(oMeinMemo);
End;
Zitat:

Zitat von uligerhardt
Damit kriegst du zwar leider keinen Compilerfehler bei unerlaubter Benutzung, aber immerhin einen deutlichen Hinweis zur Laufzeit. :mrgreen:

Ich glaube nicht, dass ich das möchte :zwinker:

@SirThornberry
Ok, überzeugt - ich lasse es, wie es ist.
Prinzipiell ist es ja auch nicht tragisch, da einfach nichts passiert, wenn der Constructor von außen aufgerufen wird.

Danke an alle.

uligerhardt 30. Jan 2008 10:27

Re: Constructor verbergen
 
Zitat:

Zitat von s-off
Zitat:

Zitat von uligerhardt
Damit kriegst du zwar leider keinen Compilerfehler bei unerlaubter Benutzung, aber immerhin einen deutlichen Hinweis zur Laufzeit. :mrgreen:

Ich glaube nicht, dass ich das möchte :zwinker:

Das glaub ich dir gern - geht mir nämlich genauso. :-)
Aber Sicherheit zur Compilezeit kriegst du bei dem Thema mit Delphi AFAICS nicht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:35 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz