Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Klasse die im Create eine Unterklasse erstellt (https://www.delphipraxis.net/103855-klasse-die-im-create-eine-unterklasse-erstellt.html)

Alloc 22. Nov 2007 19:13


Klasse die im Create eine Unterklasse erstellt
 
Hi alle,

ich habe zur Zeit das "Problem", dass ich eine Basisklasse habe von der mehrere Unterklassen (nennt man das eigentlich so?) abgeleitet sind.
Dh sowas in der Art:
Delphi-Quellcode:
TBase = class
  public
    constructor Create; override;
end;

TSub1 = class(TBase)
  public
    constructor Create; override;
end;

TSub2 = class(TBase)
  public
    constructor Create; override;
end;
Nun muss ich ja im Programm Instanzen der Sub-Klassen erzeugen. Zur Zeit wüsste ich nur, dass ich direkt im normalen Code abfrage welchen Typ ich will und dann diese Klasse erstelle (zb MyCon := TSub1.Create;).
Gibt es eine Möglichkeit, wie ich der Klasse TBase einen Konstruktor der Art Create(Typ: String); schreibe, der ich dann im Parameter zb "Sub1" übergebe, und die dann selber eine der Sub-Klassen erstellt?

Also ungefähr sowas:
Delphi-Quellcode:
type
  TBase = class
    public
      constructor Create(Typ: String);
  end;
  TSub1 = class
    public
      constructor Create;
  end;
 ...

constructor TBase.Create(Typ: String);
begin
  if Typ = 'Sub1' then
    Self := TSub1.Create;
  ...
end;

var
  MyClass = TBase;
begin
  MyClass := TBase.Create('Sub1');
end;
Wäre Klasse wenn das irgendwie ginge, oder jemand ne andre intelligente Art hat wie man sowas erledigt ;)

Grüße,
Chris

Apollonius 22. Nov 2007 19:17

Re: Klasse die im Create eine Unterklasse erstellt
 
So etwas würde ich mit einer Klassenfunktion in der Basisklasse lösen:
Delphi-Quellcode:
class function Erzeuge(Klasse: String): TBase;
Denn im Konstruktor kannst du nichts mehr ändern, da ist die Instanz schon erzeugt.

Außerdem solltest du dieses String-Konzept nach Möglichkeit vermeiden, natürlich sofern du nicht den Namen vom Benutzer kriegst. Du solltest dir vielleicht mal Klassenreferenzen anschauen...

Christian Seehase 22. Nov 2007 19:20

Re: Klasse die im Create eine Unterklasse erstellt
 
Moin Chris,

irgendwie habe ich Dein Problem nicht verstanden. :gruebel:
Wozu willst Du self etwas zuweisen? :shock:

semo 22. Nov 2007 19:46

Re: Klasse die im Create eine Unterklasse erstellt
 
Die klasse TBase ist nicht zur Verwaltung der abgeleiteten Klassen TSub1 und TSub2 gedacht,
sondern ist eine Designvorlage für die beiden Klassen:

TBase hat bestimmte properties die TSub1 und TSub2 auch besitzen.
Du erweiterst TSub1 und TSub2 aber um bestimmte properties die die Basisklasse nicht besitzt.


Frage ist was du genau bewirken willst.

Apollonius 22. Nov 2007 19:49

Re: Klasse die im Create eine Unterklasse erstellt
 
Grundsätzlich ist aber das Muster nicht falsch, z.B. kann so eine Erzeuger-Funktion recht nützlich sein, wenn man mit virtuellen Methoden arbeitet und durch Erstellung von verschiedenen Nachkommen eben entscheiden kann, welche virtuelle Methode aufgerufen wird.

inherited 22. Nov 2007 21:28

Re: Klasse die im Create eine Unterklasse erstellt
 
Am Besten erzeugst du eine Variable nach dem Motto
Delphi-Quellcode:
var
  MySub: TBase;
Und entweder erzeugst du sie je nachdem was du brauchst:
Delphi-Quellcode:
  MySub:=TSub1.Create;
Oder du erzeugst sie als TBase und castest sie dynamisch
Delphi-Quellcode:
  MySub:=TBase.Create;
  (MySub as TSub1).EigenschaftVonSub1:=42;
Da du aber nicht sagst was genau du machen möchtest können wir dir auch nicht sagen was die beste Lösung ist ;)

omata 22. Nov 2007 23:10

Re: Klasse die im Create eine Unterklasse erstellt
 
So, ich versuche mich auch mal dran...

Delphi-Quellcode:
type
  TModus = (Sub1, Sub2);

  TBase = class
    public
      constructor Create; overload; virtual; abstract;
      class function Create(Modus:TModus):TBase; overload; virtual;
  end;

  TSub1 = class(TBase)
    public
      constructor Create; override;
  end;

  TSub2 = class(TBase)
    public
      constructor Create; override;
  end;

:
:

{ TBase }

class function TBase.Create(Modus:TModus): TBase;
begin
  case Modus of
    Sub1: Result:=TSub1.Create;
    Sub2: Result:=TSub2.Create;
  end;
end;

{ TSub1 }

constructor TSub1.Create;
begin
  inherited;

end;

{ TSub2 }

constructor TSub2.Create;
begin
  inherited;

end;
Aufruf...
Delphi-Quellcode:
procedure TForm.ButtonClick(Sender: TObject);
var Base:TBase;
begin
  Base:=TBase.Create(Sub1);
  ShowMessage(Base.ClassName);

  Base:=TBase.Create(Sub2);
  ShowMessage(Base.ClassName);

  Base:=TBase.Create; // <-- löst einen "Abtrakten Fehler" aus
  ShowMessage(Base.ClassName);
end;
Gruss
Thorsten

Alloc 23. Nov 2007 00:01

Re: Klasse die im Create eine Unterklasse erstellt
 
Hi,

danke erstmal allen für die Tipps =)
Die Idee mit der Klassenmethode scheint schonmal recht gut. Daran hab ich vorher nur irgendwie nie gedacht, hab auch in Delphi noch nie mit Klassen-methoden/attributen gearbeitet gehabt ;)

@omata:
Danke für dein Code-Schnipsel, denk mal genau so könnte es gut laufen =)

@inherited:
Zitat:

Delphi-Quellcode:
var
  MySub: TBase;
...
Oder du erzeugst sie als TBase und castest sie dynamisch
Delphi-Quellcode:
  MySub:=TBase.Create;
  (MySub as TSub1).EigenschaftVonSub1:=42;

Kann das funktionieren? Wenn ich mit MySub := TBase.Create; eine Instanz von TBase erstelle, kann ich doch schlecht auf eine Eigenschaft einer Sub-Klasse zugreifen, da es ja eben eine Instanz von TBase ist?!


Hintergrund zu dem Ganzen:
Ich habe ein Programm das über verschiedene Schnittstellen auf einen Bus zugreifen soll (RS232, USB, TCP/IP-Daemon, Modem). Dh dass die Klassen natürlich fast komplett identisch sind. Der einzige Unterschied besteht in den Konfigurationsparametern. Fände es halt da extrem unpraktisch wenn man im Programmcode dann immer die Abfragen machen müsste welche Klasse man grad braucht und die dann instanziiert, wenn das auch die Basis-Klasse selber übernehmen könnte =)

Grüße,
Chris

cruiser 23. Nov 2007 04:35

Re: Klasse die im Create eine Unterklasse erstellt
 
Schnittstelle = Interface ;)

Warum definierst du nicht einfach ein Interface welches du in Interfaced Objects realisierst?

etwa so (aus dem Stehgreif jetzt):
Delphi-Quellcode:
type
  ISendMessage = interface
  ['<GUID mit STRG+SHIFT+G erzeugen>']
    procedure Send(const s: string);
  end;
 
  TTCPClass = class(TInterfacedObject, IMyInterface)
    procedure Send(const s: string);
  end;

  TUDPClass = class(TInterfacedObject, IMyInterface)
    procedure Send(const s: string);
  end;
Jetzt kannst du diese InterfacedObjects auch als ISendMessage nutzen, weil sie das Interface ja realisieren und je nachdem WIE das Interface in den Klassen realisiert wird passiert evtl. etwas anderes.

EDIT:

wenn es ums erzeugen geht.. nimm eine Enumeration und eine Erzeuger-Funktion:

Delphi-Quellcode:

type
  TConnectionType = (ctTCP, ctUDP, ctRS232, {...});


{...}

function CreateConnection(const contype: TConnectiontype): ISendMessage;
begin
  case contype of
    ctUDP: Result := TUDPClass.Create;
    ctTCP: Result := TTCPClass.Create;
  else
    // evtl. Fehlermeldung
  end;
end;

alzaimar 23. Nov 2007 07:37

Re: Klasse die im Create eine Unterklasse erstellt
 
Delphi-Quellcode:
Type
  TBase = Class...;
  TSub1 = Class (TBase)...;
  TSub2 = Class (TBase) ...;

  TBaseClass = Class Of TBase;


Function CreateClass (aClass : TBaseClass) : TBase;
Begin
  Result := aClass.Create
End;
Oder hab ich was missverstanden?

Du solltest Dir eine ClassFactory bauen. Das ist eine Klasse, die dir genau die richtigen Instanzen erzeugt, im Grunde genommen aber nichts anderes als die 'CreateClass'-Funktion ist, nur eben als Klasse.
Delphi-Quellcode:
Type
  TBaseFactory = Class
  Public
     Function CreateClass (aClass : TBaseClass) : TBase;
  End;
In der TBase-Klasse kannst Du schon rein konzeptionell keine Funktion implementieren, die Nachkommen von TBase erzeugt. TBase kann doch gar nicht wissen, was für Nachkommen auf der Welt existieren? Was ist, wenn jemand in Timbuktu von deiner TBase-Klasse ableitet? Wie soll er dann noch die TBase-Klasse ändern? Hat er immer den Quellcode parat? Dazu ist doch der ganze Vererbungsquatsch da, um eben *nicht* mehr in Basisklassen rumzufuhrwerken, wenn eine neue Ableitung hinzukommt. :gruebel:

Der obige Code mit Klassenreferenzen funktioniert immer und wird es auch immer. Wenn neue, von TBase abgeleitete Klassen hinzukommen, musst Du da gar nichts mehr ändern. Keine Enumeration hinzufügen, nix.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:11 Uhr.
Seite 1 von 2  1 2      

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