Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Basisklasse und davon abgeleitet drei Standardklassen (https://www.delphipraxis.net/101105-basisklasse-und-davon-abgeleitet-drei-standardklassen.html)

s-off 8. Okt 2007 14:50


Basisklasse und davon abgeleitet drei Standardklassen
 
Hallo zusammen,
irgendwie stehe ich gerade derbe auf dem Schlauch, und hoffe, mir kann just jemand auf die Sprünge helfen.

Folgendes:
Ich möchte eine Basisklasse TBasisklasse haben, welche ein paar Eigenschaften und ein paar Methoden hat.

Nun möchte ich von dieser Basisklasse drei Kindklassen ableiten. Diese sollen einmal die Eigenschaften und Methoden von der Basisklasse erben, aber eigentlich wie ein TEdit, TLabel bzw. TMemo sein (nur als Beispiel).

Also ungefähr so:

Delphi-Quellcode:
Type
   TBasisklasse = Class
   private
      FEigenschaft1: Integer;
      FEigenschaft2: Integer;
      FEigenschaft3: Integer;
      FWind: String;
      Procedure SetWind(Const Value: Integer);
   public
       Property Wind: String read FWind write SetWind;
   End;

   TEditklasse = Class(TBasisklasse)

   End;

   TLabelklasse = class(TBasisklasse)

   end;

   TMemoklasse = Class(TBasisklasse)

   End;
Wenn ich nun also ein Objekt aus der Klasse TEditklasse erzeuge, möchte ich im Prinzip ein TEdit haben, welches aber zusätzlich über die Eigenschaften aus TBasisklasse verfügt.
Der Grund: Wenn an 'SetWind' etwas geändert werden muss, muss dieses dann nur in der Basisklasse gemacht werden.

Ich weiß, dass sich das ziemlich wirr anhört, aber ich hoffe, dass meine Intention jemand versteht.
Ich weiss absolut nicht, wie ich das aufbauen soll :cry:

quendolineDD 8. Okt 2007 15:00

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Ich würde erstmal die Basisklasse von TObject ableiten.
Inwiefern meinst du, du willst ein TEdit, ein TLabel und ein TMemo von TBasisklasse ableiten?
Welche Proceduren willst du denn übertragen? Ich sehe nirgends ein virtual / override.

Eventuell wäre eine präzisere Formulierung deines Anliegens hilfreich ;)

Zitat:

Wenn ich nun also ein Objekt aus der Klasse TEditklasse erzeuge, möchte ich im Prinzip ein TEdit haben, welches aber zusätzlich über die Eigenschaften aus TBasisklasse verfügt.
Da TEdit ja abgeleitet wird von TBasisklasse, übernimmt es schon automatisch dessen Eigenschaften, welche in Public und in protected sich befinden.

Zitat:

Das Deklarieren einer Eigenschaft ohne Angabe eines Typs nennt man Überschreiben. Diese Vorgehensweise ermöglicht das Ändern der geerbten Sichtbarkeit bzw. des geerbten Bezeichners einer Eigenschaft. In der einfachsten Form braucht nur das reservierte Wort property zusammen mit einem geerbten Eigenschaftsbezeichner angegeben zu werden. Auf diese Weise kann die Sichtbarkeit der betreffenden Eigenschaft geändert werden. So kann beispielsweise eine in einer Vorfahrklasse als protected deklarierte Eigenschaft im public- oder published-Abschnitt einer abgeleiteten Klasse neu deklariert werden. Eigenschaftsüberschreibungen können die Angaben read, write, stored, default und nodefault enthalten, durch die die entsprechende geerbte Direktive außer Kraft gesetzt wird. Mithilfe einer Überschreibung können Sie geerbte Zugriffsangaben ersetzen, fehlende Angaben hinzufügen oder den Gültigkeitsbereich einer Eigenschaft erweitern, jedoch keine Zugriffsbezeichner entfernen oder die Sichtbarkeit verringern. Optional kann auch mit der Direktive implements die Liste der implementierten Schnittstellen ergänzt werden, ohne die geerbten Schnittstellen zu entfernen.

Die folgenden Deklarationen zeigen, wie Eigenschaften überschrieben werden können:

type
TAncestor = class
...
protected
property Size: Integer read FSize;
property Text: string read GetText write SetText;
property Color: TColor read FColor write SetColor stored False;
...
end;
type
TDerived = class(TAncestor)
...
protected
property Size write SetSize;

published
property Text;
property Color stored True default clBlue;
...
end;

Beim Überschreiben von Size wird die Angabe write hinzugefügt, damit der Wert der Eigenschaft geändert werden kann. Die Sichtbarkeit der Eigenschaften Text und Color wird von protected in published geändert. Für die Eigenschaft Color wird außerdem festgelegt, dass sie in der Formulardatei gespeichert wird, wenn sie einen anderen Wert als clBlue hat.

Wenn Sie beim Redeklarieren einer Eigenschaft einen Typbezeichner angeben, wird die geerbte Eigenschaft nicht überschrieben, sondern lediglich verdeckt. Dadurch wird eine neue Eigenschaft mit demselben Namen wie die geerbte erstellt. Diese Art der Deklaration muss immer vollständig vorgenommen werden. Stets muss zumindest eine Zugriffsangabe vorhanden sein.

Unabhängig davon, ob eine Eigenschaft in einer abgeleiteten Klasse verdeckt oder überschrieben wird, erfolgt die Suche nach der Eigenschaft immer statisch. Der deklarierte (also zur Compilierzeit bekannte) Typ der Variablen bestimmt die Interpretation des Eigenschaftsbezeichners. Aus diesem Grund wird nach dem Ausführen des folgenden Codes durch das Lesen oder Schreiben von MyObject.Value die Methode Method1 bzw. Method2 aufgerufen, obwohl MyObject eine Instanz von TDescendant enthält. Sie können aber durch eine Typumwandlung in TDescendant auf die Eigenschaften und Zugriffsangaben der abgeleiteten Klasse zugreifen.

type
TAncestor = class
...
property Value: Integer read Method1 write Method2;
end;
TDescendant = class(TAncestor)
...
property Value: Integer read Method3 write Method4;
end;
var MyObject: TAncestor;
...
MyObject := TDescendant.Create;

mkinzler 8. Okt 2007 15:02

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Von TObject brauchst du nicht explizit ableiten, da das auf jeden Fall geschieht. Jede Klasse in Delphi erbt automatisch direkt oder indirekt von TObject.

Sidorion 8. Okt 2007 15:06

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Das was Du benötigst ist ein Interface und eine zugehörige Delegatenklasse. Such mal in der OH nach 'Interface' und 'implements'. Das Interface schreibst du dann zusätzlich in die Klassendeklaration (=class(TBasisklasse,Interface)). In dem Interface implementierst Du dann die Methoden, die jetzt deine Basisklasse besitzt. Interfaces umgehen das Problem, dass in Delphi keine Mehrfachvererbung möglich ist.

s-off 8. Okt 2007 15:13

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von quendolineDD
Ich würde erstmal die Basisklasse von TObject ableiten.

Da bin ich mkinzlers Meinung ;)

Zitat:

Zitat von quendolineDD
Eventuell wäre eine präzisere Formulierung deines Anliegens hilfreich ;)

Wenn das so einfach wäre :?

Also:
Erzeuge ich mir ein Objekt von TEditklasse, dann möchte ich, dass auf meiner Form ein TEdit erscheint, welches aber zusätzlich die Eigenschaft 'Wind' aus der Basisklasse besitzt.
Erzeuge ich mir ein Objekt von TLabelklasse, dann möchte ich, dass auf meiner Form ein TLabel erscheint, welches aber zusätzlich die Eigenschaft 'Wind' aus der Basisklasse besitzt.
Erzeuge ich mir ein Objekt von TMemoklasse, dann möchte ich, dass auf meiner Form ein TMemo erscheint, welches aber zusätzlich die Eigenschaft 'Wind' aus der Basisklasse besitzt.

Muss ich Änderungen an 'SetWind' vornehmen, so mache ich das nur in der Basisklasse - die Änderungen übertragen sich auf die drei Kindklassen.
Dass das so, wie ich es oben dargestellt habe, nicht funktionieren kann, ist klar. Sollte das Ganze nur veranschaulichen.

Werde mir das mit den Interfaces von Sidorion mal zu Gemüte führen.

Jelly 8. Okt 2007 15:16

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Das wird so nicht gehen. Und zwar weil du erweiterte Klassen von TEdit, TMemo und TLabel haben willst. Deine TBasisklasse kann aber nicht von allen 3 erben.

Es bleibt dir wohl nichts anderes übrig, als 3 neue Unterklassen von TEdit, TMemo und TLabel zu erstellen, und dort jeweils als Referenz auf deine TBasisklasse zu referieren (Assoziation im UML Jargon)

s-off 8. Okt 2007 15:20

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Jelly
Es bleibt dir wohl nichts anderes übrig, als 3 neue Unterklassen von TEdit, TMemo und TLabel zu erstellen, und dort jeweils als Referenz auf deine TBasisklasse zu referieren (Assoziation im UML Jargon)

Und das geht mit den von Sidorion gennanten Interfaces? Oder geht das wieder in eine andere Richtung. (Kam noch nicht soweit, das Thema 'Interface' in der Hilfe nachzuschlagen.)

Phoenix 8. Okt 2007 15:26

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zu meiner Schande habe ich in Delphi noch nie mit Interfaces gearbeitet, aber wenn die so funktionieren wie in .NET, dann hilft das nicht.

In dem Fall wäre ein interface nur eine Erweiterung der Klasse die sagt: "Diese Klasse hier hat diese Properties und diese Methoden.". Die Implementierung des Interfaces - im konkreten Fall die SetWind Methode und das Property Wind - müssen jedoch auf jeder Klasse die das Interface verwendet selber implementiert werden.

Apollonius 8. Okt 2007 15:28

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
In Interfaces kannst du nur Methoden und Propertys, aber keine Felder definieren, außerdem keine Implentierung, also nur abstrakt. Und dann müsstest du in jeder Klasse den Code für SetWind einfügen.
Das sind solche Fälle, in denen man sich echte Mehrfachvererbung wie in C++ wünscht.

s-off 8. Okt 2007 15:30

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Hmm,

Interface scheint tatsächlich nicht das Richtige zu sein.
Dort habe ich ja keine Möglichkeit Felder zu deklarieren.

Edit: Wie Apollonius sagt :wink:

Aber nochmal: Mehrfachvererbung würde ja bedeuten, dass meine TBasisklasse von den drei Standardklassen erben würde.
Ich möchte es aber ja genau andersrum: Die drei Standardklassen sollen ja die Felder und Methoden der Basisklasse erben.

mkinzler 8. Okt 2007 15:31

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Mehrfachvererbung bringt mehr Probleme als Vorteile, deshalb findet man sie nicht in neuren Sprachen wie Java, Delphi, C#, ..., wo man Vererbung per Interfaces präferiert.

s-off 8. Okt 2007 15:34

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von quendolineDD
Da TEdit ja abgeleitet wird von TBasisklasse, übernimmt es schon automatisch dessen Eigenschaften, welche in Public und in protected sich befinden.

Ähm, das ist mir schon klar - ein bissel OOP verstehe ich schon, aber:
TEdit wird nicht von Basisklasse abgeleitet.
Ich möchte eine Klasse, deren Instanz der eines TEdit entspricht, zusätzlich aber die Eigenschaften aus TBasisklasse übernimmt.

Und wie ich schon schrieb: so, wie ich das im Delphi-Code meines ersten Beitrages dargestellt habe, kann das nicht funktionieren; das weiß ich. Aber genau dort liegt ja mein Problem - ich weiß nicht, wie ich dieses Konstrukt erzeugen soll.

Edit:
was ich nicht möchte, ist soetwas:
Delphi-Quellcode:
Type
   TEditklasse = Class(TEdit)
   private
      FEigenschaft1: Integer;
      FEigenschaft2: Integer;
      FEigenschaft3: Integer;
      FWind: String;
      Procedure SetWind(Const Value: Integer);
   public
       Property Wind: String read FWind write SetWind;
   End;

   TLabelklasse = class(TLabel)
   private
      FEigenschaft1: Integer;
      FEigenschaft2: Integer;
      FEigenschaft3: Integer;
      FWind: String;
      Procedure SetWind(Const Value: Integer);
   public
       Property Wind: String read FWind write SetWind;
   end;

   TMemoklasse = Class(TMemo)
   private
      FEigenschaft1: Integer;
      FEigenschaft2: Integer;
      FEigenschaft3: Integer;
      FWind: String;
      Procedure SetWind(Const Value: Integer);
   public
       Property Wind: String read FWind write SetWind;
   End;

Apollonius 8. Okt 2007 15:55

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Mehrfachvererbung wäre hier sehr praktisch. Du könntest einfach schreiben
Delphi-Quellcode:
 TEditklasse=class(TEdit, TBasisklasse)
und fertig wärst du. Ich habe mir auch schon eine weniger eingeschränkte Form der Mehrfachvererbung gewünscht, als es sie in Delphi gibt. Das Diamond-Problem (das meintest du doch, mkinzler?!) wurde in C++ ja sehr gut mit virtueller Vererbung gelöst, und die Spezialfälle, bei denen es vorkommt, ließen sich bestimmt auch anders vermeiden oder verbieten.

s-off 8. Okt 2007 16:00

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Apollonius
Mehrfachvererbung wäre hier sehr praktisch. Du könntest einfach schreiben
Delphi-Quellcode:
 TEditklasse=class(TEdit, TBasisklasse)

Ja, das wäre was :-D

Wenn doch so viele Leute eine solche Funktionalität gerne hätten - gibt es dann keinen 'Workaround'?
Interfaces sind es ja aufgrund der nicht vorhandenen Möglichkeit, Felder etc. zu deklarieren, nicht.

Und nein - für mich ist kein Workaround, das Ganze in C-basierten Sprachen zu realisieren :wink:
Abgesehen davon, dass ich kein C[x] beherrsche, sind mir meine Arbeitsmittel vorgegeben.

Khabarakh 8. Okt 2007 16:27

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
An Workarounds mangelt es nicht, dafür müsste man aber erst etwas mehr von den Hintergründen erfahren; man möchte schließlich das freakigstmögliche Design-Pattern einsetzen ;) . Z.B. könnte es sinnvoll sein, das ganze als Factory-Interface zu gestalten:
Delphi-Quellcode:
type
  IMyFactory = interface
    function CreateSomething : TBasisklasse;
  end;

[...]

function TMyEdit.CreateSomething;
begin
  Result := TEditklasse.Create;
end;
Oder auch einfach als
Delphi-Quellcode:
type
  IMyExtender = interface
    function GetSomething : TBasisklasse;
    property Something : TBasisklasse read GetSomething;
  end;
(Alle Angaben ohne Gewähr, hab Interfaces in Delphi nur ein-, zweimal benutzt)

s-off 8. Okt 2007 16:44

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Khabarakh
man möchte schließlich das freakigstmögliche Design-Pattern einsetzen ;)

:mrgreen:

Naja, zu den Hintergründen - den Sinn habe ich ja bereits erläutert, und ich sehe ein, dass Mehrfachvererbung eine nette Sache wäre.

Ich habe es jetzt so gelöst, dass ich einfach in der Basisklasse ein Feld 'FControl' und eine entsprechende Property dazu erstellt habe, dem ich dann im Constructor, den ich in den Kindklassen überschreibe, einfach eine Instanz der entsprechenden Klasse zuweise, und erst danach den Constructor der Basisklasse aufrufe.
Dann spreche ich das Ganze halt hinterher nicht nur mit dem Instanzennamen an, sondern mit Instanzenname.Control
Mit Mehrfachvererbung hätte mir zwar besser gefallen, aber so gehts auch.

Delphi-Quellcode:
   TBasisklasse = Class
   private
      FControl: TControl;
      FEigenschaft1: Integer;
      FEigenschaft2: Integer;
      FWind: Integer;
      Procedure SetWind(Const Value: Integer);
   public
      Constructor Create(AOwner: TComponent); virtual;
      Property Control: TControl read FControl;
      Property Wind: Integer read FWind write SetWind;
   End;

   TEditklasse = Class(TBasisklasse)
   public
      Constructor Create(AOwner: TComponent); override;
   End;

   TLabelklasse = Class(TBasisklasse)
      Constructor Create(AOwner: TComponent); override;
   End;

   TMemoklasse = Class(TBasisklasse)
      Constructor Create(AOwner: TComponent); override;
   End;

[...]

Constructor TBasisklasse.Create(AOwner: TComponent);
Begin
   FEigenschaft1: FControl.Width;
   FEigenschaft2: FControl.Height;
End;

Procedure TBasisklasse.SetWind(Const Value: Integer);
Begin
   FWind := Value;
   FControl.Width := FEigenschaft1 * Value;
   FControl.Height := FEigenschaft2 * Value;
End;

Constructor TEditklasse.Create(AOwner: TComponent);
Begin
   FControl := TEdit.Create(AOwner);
   Inherited;
End;

Constructor TLabelklasse.Create(AOwner: TComponent);
Begin
   FControl := TLabel.Create(AOwner);
   Inherited;
End;

Constructor TMemoklasse.Create(AOwner: TComponent);
Begin
   FControl := TMemo.Create(AOwner);
   Inherited;
End;
Edit: freue mich natürlich noch immer über anderweitige Lösungsmöglichkeiten, wenn Ihr welche habt :stupid:

Hansa 8. Okt 2007 18:46

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Hier steht nicht viel brauchbares ! Das einzige wäre ein Tedit und ein TMemo. Die besitzen zumindest mal Editier-Funktionalitäten. Ein TLabel hat nicht mal die. Wozu soll dieser unzusammenhängende Kram jetzt zusammengeschmissen werden ? Wird ein spezielles TEdit gebraucht, dann leite das von TEdit ab usw. Die Funktionalität bei TObject (= bei Null) etc. angefangen selber einzubauen ist völliger Blödsinn. :mrgreen:

Dax 8. Okt 2007 18:55

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Wenn ich mich jetzt nicht vollkommen vertue, könnten Delphi-Referenz durchsuchenClass Helpers was für dich sein. Das sind Klassen, die du an die Klasse, der sie "helfen", direkt anheftest. Die Klasse hat also zusätzlich diese Felder, Methoden, ... Einzige Einschränkung ist, dass die Unit mit den Helferklassen in der uses-Klausel der verwendenden Units stehen muss.

Jens Schumann 8. Okt 2007 19:02

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Hallo,
wenn ich mich recht erinnere gibt es für Delphi mittlerweile ClassHelper.
Mal hier im Forum suchen. Wenn man keine property sondern nur eine
Setter und Getter Methode für WInd verwendet könnte man einen
Classhelper verwenden.

Apollonius 8. Okt 2007 19:02

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Ich habe auch schon daran gedacht, aber Helferklassen können keine Felder enthalten.

s-off 8. Okt 2007 21:06

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Hansa
Hier steht nicht viel brauchbares !

Das mag wohl sein. Wenn ich etwas brauchbares anzubieten hätte, müsste ich hier nicht um Hilfe bitten.

Zitat:

Zitat von Hansa
Das einzige wäre ein Tedit und ein TMemo. Die besitzen zumindest mal Editier-Funktionalitäten. Ein TLabel hat nicht mal die. Wozu soll dieser unzusammenhängende Kram jetzt zusammengeschmissen werden ?

Diese drei Standardklassen sind Beispiele. Es ist dabei vollkommen egal, was die können, ob sie eine Editiermöglichkeit bieten, oder sonstetwas.

:!:
Vielleicht ein kurzer Satz zur Erläuterung.
Seitens meines Arbeitgebers bin ich sehr eingeschränkt, was die Herausgabe von Informationen betrifft.
Ich darf mich zwar hier im Forum aufhalten, darf auch Fragen stellen und Antworten geben - ich darf allerdings keinerlei Originalquellcode - und seien es nur Variablennamen - veröffentlichen, der in irgendeinem Zusammenhang mit unserem Projekt steht; dafür musste ich sogar unterschreiben.

Über Sinn und Unsinn dieser Richtlinie kann man streiten - möchte ich aber nicht, da ich - und auch niemand anderes - etwas daran ändern kann.

Aus diesem Grund muss ich alles, was ich hier reinposte, irgendwie abstrahieren - dabei kommt dann gelegentlich auch etwas zusammenhangloses Zeugs heraus.

Daher habe ich - so dachte ich zumindest - eindeutig geschildert, was ich haben möchte.
Da das anscheinend nicht der Fall ist, versuche ich es nocheinmal.

Ich muss dynamisch verschiedene Controls erzeugen. Nehmen wir beispielsweise(!) TEdit, TCheckbox und TComboBox.
Alle diese drei Controls müssen mit einer zusätzlichen Funktionalität ausgestattet werden. Nennen wir diese Funktionalität 'Sag mir Deinen Startwert' (nur als Beispiel!).
So, alle diese Controls werden mit einem Startwert (Text, Checked, Text) belegt.
Dieser kann zur Laufzeit geändert werden.
Irgendwann sollen mir diese Controls auf Zuruf ihren Startwert mitteilen.

Ich erzeuge mir also für alle 3 Controls eine eigene Klasse.
Diese Klasse bekommt ein Feld FStartwert. In diesem wird der Initialwert gespeichert, sobald das Objekt erzeugt worden ist.
Jetzt gibt es zusätzlich die Public-Funktion 'GibStartwert'. Diese malt dem Startwert (FStartwert) ein paar Blümchen aufs Hemd und gibt ihn in einer Message aus. Fertig.

So, jetzt kann ich allen diesen 3 abgeleiteten Klassen (TMeinEdit, TMeineCheckbox und TMeine ComboBox) das Feld FStartwert und die Methode GibStartwert geben.
Bei allen sähe die Methode GibStartwert gleich aus.

Müsste ich nun an dieser Methode etwas ändern, so müsste ich das in allen drei Klassen tun.

Und das ist der Knackpunkt, wo ich denke, dass das aus Sicht der OOP nicht so günstig ist.

Also dachte ich mir - erzeuge ich mir eine Basisklasse, die das Feld FStartwert und die Methode GibStartwert hat, und leite dann meine 3 Controls davon ab - naja, den Rest kennt ihr ja.

Ich hoffe, dass mein Vorhaben - auch wenn es wieder abstrahiert ist - etwas deutlicher wurde.

Dax 8. Okt 2007 21:16

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Delphi-Quellcode:
type
  IStartwert = interface
    function GibStartwert: string;
  end;

  TStartwert = class(TInterfacedObject, IStartwert)
  private
    fStartwert: string;
  public
    function GibStartwert: string;

    constructor Create(startwert: string);
  end;

  TEditEx = class(TEdit, IStartwert)
  private
    fStartwert: TStartwert;
  public
    property Startwert: IStartwert read fStartwert implements IStartwert;

    constructor Create;
  end;


function TStartwert.GibStartwert: string;
begin
  Result := fStartwert;
end;

constructor TStartwert.Create(startwert: string);
begin
  inherited Create;
  fStartwert := startwert;
end;

constructor TEditEx.Create;
begin
  inherited Create;
  fStartwert := TStartwert.Create('blubb');
end;
Ich weiß nicht, ob es direkt kopiert so funktioniert (hab kein Delphi, es zu testen), aber im Prinzip dürfte das doch deinen Anforderungen entsprechen..?

Hansa 8. Okt 2007 21:26

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von s-off
...Ich erzeuge mir also für alle 3 Controls eine eigene Klasse.
Diese Klasse bekommt ein Feld FStartwert. In diesem wird der Initialwert gespeichert, sobald das Objekt erzeugt worden ist.
Jetzt gibt es zusätzlich die Public-Funktion 'GibStartwert'. Diese malt dem Startwert (FStartwert) ein paar Blümchen aufs Hemd und gibt ihn in einer Message aus. Fertig.

So, jetzt kann ich allen diesen 3 abgeleiteten Klassen (TMeinEdit, TMeineCheckbox und TMeine ComboBox) das Feld FStartwert und die Methode GibStartwert geben.
Bei allen sähe die Methode GibStartwert gleich aus.

Müsste ich nun an dieser Methode etwas ändern, so müsste ich das in allen drei Klassen tun.

Und das ist der Knackpunkt, wo ich denke, dass das aus Sicht der OOP nicht so günstig ist.
..

Du wärst schon lange fertig, wenn die 3 Komponenten jeweils eine property mehr hätten. Benutze besser diese drei, als eine letztenendes unbrauchbare Hyperklasse zu machen. Und den Ober-Aufsehern würde ich mal sagen, dass sie übertreiben (Variablennamen ? :shock: ) und dadurch kontraproduktiv sind. Ich lasse teilweise bewusst Quelltexte vor Ort. Wer will denn damit was anfangen ? Irgenswo steht in der uses immer eine Unit, die nicht da ist und die sind dann trotz guter Kommentierung völlig am Ende. :mrgreen:

s-off 8. Okt 2007 21:51

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
@Dax:
Prinzipiell ist erfüllt es seinen Dienst, ja.
Aber: da hat dann ja jede Klasse ein Feld und eine zusätzliche Property die ich explizit in der Klasse angeben muss.
Ich weiss, dass ist - ähm - Kleinscheisserei, aber wenn es nur so geht - dann geht es halt nur so - danke :zwinker:
Zu den Helferklassen komm eich gleich.

@Hansa:
Ja, eine zusätzliche Property - das war ja halt die Frage, ob OOP nicht minimalistisch arbeitet; aber anscheinend ja nicht.
Den Ober-Häuptlingen kann man leider nicht reinreden.

@Apollonius, Jens Schumann und Dax:
Helferklassen helfen hier tatsächlich. Und es können sogar Klassenfelder erzeugt werden :-D
Das Ganze sieht dann so aus (wieder abstrahiert):
Delphi-Quellcode:
   TMyEdit = Class(TEdit)
   public
      Constructor Create(AOwner: TComponent); override;
   End;

   TMyClassHelper = Class helper For TMyEdit
   Class Var
         FStartwert: String;
         Procedure GibStartwert(_sPrefix: String);
      End;

Hawkeye219 8. Okt 2007 22:12

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Hallo,
Zitat:

Zitat von s-off
Und es können sogar Klassenfelder erzeugt werden

Dir ist aber schon klar, daß sich alle Instanzen ein einziges Klassenfeld teilen, oder? Mit anderen Worten: du kannst in dem Feld nicht für jede Instanz einen anderen Wert ablegen.

Gruß Hawkeye

s-off 9. Okt 2007 06:13

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Guten Morgen.
Zitat:

Zitat von Hawkeye219
Dir ist aber schon klar, daß sich alle Instanzen ein einziges Klassenfeld teilen, oder? Mit anderen Worten: du kannst in dem Feld nicht für jede Instanz einen anderen Wert ablegen.

Danke für den Hinweis. Soweit ist es allerdings nicht gekommen :wink:
Nach langem hin und her habe ich mich letztendlich doch dazu entschlossen, von den benötigten Standardklassen abzuleiten, und dort die jeweilige Funktionalität direkt einzubauen.

Nichts desto trotz war dieser Thread wiedermal eine Erfahrung und ich habe etwas dazu gelernt: Interfaces und Helferklassen - danke an alle, die mir in diesem Thread geantwortet haben :!:

Und nebenbei werde ich mich dann noch mal dem Thema 'Assoziation' widmen - danke hier an Jelly :wink:

Sidorion 9. Okt 2007 09:01

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Na da hört mal wieder keiner zu :zwinker: . Dein Problem löst sich wie folgt:
Delphi-Quellcode:
Type
  // Interface, das kriegen alle drei Klassen
  IMyInterface=interface(IInterface)
//hier kommt dann ne GUID, die wird automatisch erzeugt
   procedure MyWind;
  end;
  //Helperklasse für das Interface. Diese weiss, was zu tun ist, wenn die Methoden gerufen werden
  TMyIntfHelper=Class(TObject)
   FMemberusw: Typ;
  public
   procedure MyWnd;
  end;
  // ein Beispiel
  TMyEdit=Class(TEdit,IMyInterface)
   private
    FHelper: TMyIntfHelper;
   ...

   public
    property MyHelper: TMyIntfHelper Read FHelper implements IMyInterface;
  end;
  // mehr ist in TMyEdit im prinzip nicht zu schreiben, damit das Interface implementiert wird
TMyIntfHelper ist ein Delegat, der alle Methoden von IMyInterface implementiert. Dieser muss nun in jeder Klasse, die IMyInterface deklariert instanziert werden und erledigt dort die Drecksarbeit. Jetzt kannst Du problemlos das von TEdit geerbte TMyEdit als IMyInterface ansprechen und die Methoden benutzen. Das selbe würde dann für alle anderen Klassen mit dem Interface gelten.
Der Schlüssel liegt sozusagen in der Direktive Implements. Die sorgt dafür, dass die angegebene Property für die Bearbeitung des Interfaces sorgt. Die Klasse selber muss sich darum nichtmehr kümmern.
Dieses Konstrukt ist wesentlich eleganter, als Mehrfachvererbung, da hier das Diamantproblem garnicht entstehen kann, jedoch alle Möglichkeiten gegeben sind.
Nachtrag: Jetzt kannst Du einfach TMyEdit.MyWind rufen, alsob das Interface direkt in TMyEdit implementiert wäre.

s-off 9. Okt 2007 09:34

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Sidorion
Na da hört mal wieder keiner zu :zwinker:

Nun - gehört schon, aber nicht verstanden :wink:
Wahrscheinlich war das auch genau die 'eine Property', die Hansa meinte.

Ich werde mir das Ganze mal verinnerlichen - vielen Dank :-D

Edit: Eine Frage habe ich dennoch:

Wie kann ich denn jetzt in TMyIntfHelper.MyWind auf Eigenschaften des späteren Edits zugreifen?
Ich habe also in TMyIntfHelper einige Felder. Diese muss ich der Methode MyWind den Eigenschaften des späteren Edits zuweisen, bspw so:

Delphi-Quellcode:
  TMyIntfHelper=Class(TObject)
   FEinString: String;
  public
   procedure MyWind;
  end;

 Procedure TMyIntfHelper.MyWind
 begin
   MeinSpäteresEdit.Text := FEinString;
 end;
MeinSpäteresEdit kennt er ja nicht. Gibt es da irgendwie eine Art Platzhalter?

Sidorion 9. Okt 2007 10:40

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Na du könntest beispielsweise den Helper von TControl ableiten. Dann wird in den Owner (THelper.Create(Self)) das Objekt geschrieben und du kannst dann im Helper über den Owner und RTTI (Unit Typinfo) zugreifen. Du kannst auch einen Event im Helper deklarieren, im Konstruktor Methodenzeiger übergeben usw.
Dir stehen hier sämtliche Objektkommunikationsmöglichkeiten offen.

Jelly 9. Okt 2007 12:37

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Sidorion
Jetzt kannst Du einfach TMyEdit.MyWind rufen, alsob das Interface direkt in TMyEdit implementiert wäre.

Sollte das nicht myEdit.MyWind heissen. Oder greifst du tatsächlich direkt über die Klasse zu und nicht über die Instanz.

Das ist eine interessante Sache, mit dem "implements". Das kannte ich noch nicht. Werd mir das heut abend aber auch mal reinziehen.

Apollonius 9. Okt 2007 12:41

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Besonders interessant ist, dass Interface- und Klassen-Propertys ganz unterschiedlich gehandhabt werden. Bei Interface-Propertys z.B. erhält die eigentliche Kasse gar keine eigene Interface-VMT, bei Klassen-Propertys schon.

Sidorion 9. Okt 2007 12:58

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
@jelly: natürlich musst Du die Methode bei einer Instanz rufen. Ich hab das T nur hingeschrieben, um zu zeigen, dass kein Cast oder Umweg über die implementierende Property notwendig ist.
Allerdings geht das nur, wenn Du eine Variable vom Typ TMyEdit hast. Ist die Variable vom Typ TEdit oder weiterer Vorgänger, musst Du erst auf das Interface casten (mit As) oder auf eine Variable vom Typ des Interfaces zuweisen (Achtung hier kommt es zu Ausnahmen wenn wirklich eine Instanz von TEdit angelegt wurde).

Ach ja: Interfaces bringen eine Referenzzählung mit (das macht schon IInterface bzw. TInterfacedObject). Willst Du diese Klassen dann benutzen, musst Du sie in eine Variable des Interfacetyps instanzieren oder in der Helperklasse die Referenzzählung unterdrücken. Steht auch irgendwo in der OH. Ansonsten wird die Inszanz gleich nach dem Konstruktoraufruf wieder weggeschmissen.
Beispiel:
Delphi-Quellcode:
Var
  iMyEdit: IMyInterface;
Begin
  iMyEdit:=TMyEdit.Create(..);
End;

Kedariodakon 9. Okt 2007 13:14

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Sidorion
Ich hab das T nur hingeschrieben, um zu zeigen, dass kein Cast oder Umweg über die implementierende Property notwendig ist.

Hmm also bei mir ist das sehr wohl der Fall, ich muss immer über das Property MyHelper zu MyWind, also "(aObj as TMyEdit ).MyHelper.MyWind", also "(aObj as TMyEdit ).MyWind" tut es bei mir nicht.. (Delphi 7)


Bye Christian

Dax 9. Okt 2007 13:31

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Is ja süß, man muss immer den Umweg über eine Interface-Variable gehen..

Sidorion 9. Okt 2007 16:05

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Nein. Es reicht ein Cast. (MyObj As IMyInterface).MyWnd.
Wie gesagt, wenn man mit Interfaces arbeitet sollte man sowieso Interfacevariablen nutzen. Ist sozusagen eine weitere Abstraktionsstufe. Bei Objektorientierung habe ich einen schwarzen Kasten (einer bestimmten Art), an dessen Henkeln ich runschraube. Mit Interfaces Interessiert mich nichtmal mehr der Kasten, sondern nur noch, dass er bestimmte Henkel hat, an denen ich rumschrauben kann.

Ein Interface ist jedenfalls das einzige Sprachkonstrukt in Delphi mit dem sowas geht. Mehrfachvererbung iss ja nicht.

Dax 9. Okt 2007 16:16

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Zitat von Sidorion
Nein. Es reicht ein Cast. (MyObj As IMyInterface).MyWnd.

Dann muss sich das seit Delphi 6 geändert haben :gruebel:

shmia 9. Okt 2007 16:38

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Zitat:

Ich muss dynamisch verschiedene Controls erzeugen. Nehmen wir beispielsweise(!) TEdit, TCheckbox und TComboBox.
Alle diese drei Controls müssen mit einer zusätzlichen Funktionalität ausgestattet werden. Nennen wir diese Funktionalität 'Sag mir Deinen Startwert' (nur als Beispiel!).
So, alle diese Controls werden mit einem Startwert (Text, Checked, Text) belegt.
Dieser kann zur Laufzeit geändert werden.
Irgendwann sollen mir diese Controls auf Zuruf ihren Startwert mitteilen.
Um deine Gedanken mal in eine ganz andere Richtung zu lenken:
Warum müssen die zusätzlichen Properties so eng mit den Controls verkoppelt werden ?
Es gibt ja auch das Model-View-Controller Prinzip.
Angenommen dein Modell wäre eine elektronische Schaltung mit vielen Bauteilen.
Jedes Bauteil hat unterschiedliche Properties (Widerstand, Kapazität,...).
Der View muss dynamisch zur Laufzeit aufgebaut und mit Controls versehen werden.
Anstatt nun die Controls mit zusätzlichen Properties auszustatten, könnte man doch eher
den View als Objektmodell (TResistor, TWire, TDiode, ...) aufbauen und dort alle Properties unterbringen.
Im View gibt es nun eine Liste, in der vermerkt ist, welches Control an welches Bauteil angekoppelt ist.
==> alle Controls bleiben Standard sind aber an das Modell gekoppelt

s-off 9. Okt 2007 17:20

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von shmia

Ohje. Und wieder was Neues :? Ich bin ja einerseits wirklich dankbar für die vielen neuen Vorschläge, aber ehrlich gesagt bin ich gerade etwas überfordert, das Ganze zu sortieren. Sei mir nicht böse, shmia, aber ich kann mich damit erst später auseinandersetzen, wenn ich das mit den Interfaces verstanden habe - ansonsten komme ich aus dem Chaos gar nicht mehr hinaus :roll:

Also, ich habe nun mal eine Beispielanwendung, basierend auf Sidorions Posts geschrieben.
Habe mir dieses Mal auch ein etwas sinnvollerers Beispiel überlegt, damit das Ganze etwas anschaulicher wird.

Standardcontrols (Label, Edit etc.) sollen eine Zoommöglichkeit bekommen (das ist wieder nur ein Beispiel - bitte keine anderen Wege aufzeigen, wie man die Dinger zoomen kann - es geht mir jetzt um das Prinzip mit den Interfaces :wink: )

Beim Erzeugen der Mainform werden ein Label und ein Edit erzeugt (liegen beide übereinander, ist aber jetzt auch egal).
Mittels des SpinEdits sollen die beiden vergrößert bzw. verkleinert werden.

Die Probleme:
Bei Betätigung des SpinEdits gibt es eine Zugriffsverletzung in der Zoom-Methode.
Die Create-Methode der TBasisklasse (des Helfers) wird nicht aufgerufen - hätte erwartet, dass diese beim Erzeugen der Controls aufgerufen wird. Da habe ich halt das beschriebene Verständnisproblem mit der Kommunikation zwischen Objekt, Interface und Helferklasse.

Hoffe, mir kann jemand weiterhelfen.

Und bitte dran denken - es geht mir jetzt nur um das Prinzip mit diesen Interfaces. Ob diese Art zu zoomen schön ist, oder nicht, ist in diesem Falle vollkommen egal. Das soll nur dem besseren Verständnis meines Anliegens diesen - danke.

Apollonius 9. Okt 2007 17:48

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Wie kommt denn die TBasisklasse in den FHelper? Du kannst nur mit Interfaces arbeiten, die nicht nil sind. Folglich muss der Konstruktor von TEditklasse und TLabelklasse überschrieben werden.
Zur Sache mit dem Cast: Da habe ich auch schon mal dran gehangen. Der Trick ist, dass der internen Cast-Funktion eine GUID übergeben werden muss. Verpasse ITestInterface also eine GUID. Bei Interfaces musst du übrigens zwingend mit dem as-Cast arbeiten, der function-syle-Cast führt fast zwingend zur Zugriffsverletzung, da in der falschen VMT die Funktion gesucht wird (ich will jetzt nicht mit den Interna langweilen, aber wer will, kann ja mal schauen, wie Interface-Methoden eigentlich aufgerufen werden).

s-off 9. Okt 2007 18:04

Re: Basisklasse und davon abgeleitet drei Standardklassen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Apollonius
Wie kommt denn die TBasisklasse in den FHelper? Du kannst nur mit Interfaces arbeiten, die nicht nil sind. Folglich muss der Konstruktor von TEditklasse und TLabelklasse überschrieben werden.

Ähm - ja - klingt logisch.
Habe nun das Create der Objekte überschrieben und weise darin FHelper eine Instanz der Basisklasse zu - so:
Delphi-Quellcode:
Constructor TLabelklasse.Create(AOwner: TComponent);
Begin
   Inherited;

   FHelper := TBasisklasse.Create(self);
End;
Zitat:

Zitat von Apollonius
Der Trick ist, dass der internen Cast-Funktion eine GUID übergeben werden muss.

Hui - Sidonius hatte ja in seinem ersten Beispielcode geschrieben, dass eine GUID benötigt würde. Er schrieb aber auch, dass diese automatisch erzeugt wird, was bei mir aber anscheinend nicht der Fall war - ist mir aber ehrlich gesagt auch gar nicht aufgefallen, dass diese fehlte. STRG+UMSCH+G hat geholfen.
Nun kann ich so casten:
Delphi-Quellcode:
(oEdit As ITestInterface).Zoom(SpinEdit1.Value);
Nun ja, ich habe wie gesagt, die Create-Methode überschrieben und das casten angepasst.
Ich bekomme nun zumindest schonmal keine Zugriffsverletzung mehr - das gewünschte Zoomen funktioniert aber trotzdem noch nicht - genauer gesagt passiert gar nichts, wenn ich den SpinEdit ändere.
Naja, mal sehen, wo 's hängt.

Danke erstmal, dass ich soweit gekommen bin ;)

Edit: das Zoomen funktioniert nicht, da die Initialwerte im Create der Basisklasse alle als 0 ankommen.
Ich dreh hier nochmal am Reifen.... :wall:

Edit: Habe mal eine aktualisierte Version hochgeladen

Sorry, aber bei mir hat's schon immer etwas länger gedauert, bis es 'klick' gemacht hat :?


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:41 Uhr.
Seite 1 von 2  1 2      

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