Autor Beitrag
combatman
Hält's aus hier
Beiträge: 13



BeitragVerfasst: Mo 24.06.02 13:09 
Ich habe ein betriebswirtschaftliches Problem zu lösen, für das es verschiedene Lösungsansätze gibt. Also habe ich eine Basisklasse programmiert, die quasi protected deklarierte Tools enthält und eine abstrakte, virtuelle Methode solve. In Java ist so was ein Interface.

Nun will ich folgendes tun: Ich bilde Subklassen dieser Klasse, in denen ich verschiedene Lösungsmethoden implementiere (Brute Force, Branch&Bound, usw.).

Nun aber mein Problem: Im Hauptprogramm möchte ich eine Methode plugin(name, Klasse); programmieren, die folgendes tut:
- den Namen in eine Dropdownliste einfügen, wo der Benutzer das
Verfahren auswählen kann
- die Klasse (Wichtig: Die Klasse! Keine Instanz!) in eine Liste
einfügen

Da liegt nun mein Problem. Ich möchte ja nicht schon beim Programmstart tausend Instanzen bilden (die ja dann alle schon die Daten halten) und nur die Instanzen per case-Auswahl aufrufen, das wäre ja etwas billig und unflexibel. Außerdem möchte ich so was mal probieren, weil das Bankingprogramm u.U. dann auch verschiedene Module als Plugins unterstützen soll.

Vielmehr möchte ich zur Laufzeit anhand des Indizes der Dropdownlist die richtige Klasse instantiieren und ihre solve-Methode aufrufen. Dummerweise scheint das nicht so richtig zu gehen.

Wenn ich so was in der Art tue:

Klasse A
Klasse B (abgeleitet von A)
Klasse C (abgeleitet von A)
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
Hauptprogramm bei Startbuttonklick:
Var x  :A;
Begin
  x:=B.create; (B ist aus der Auswahlliste entnommen, könnte auch C sein)
  x.solve;
End;

Dann ruft er die Methode solve aus der Klasse A auf und beschwert sich mit "abstrakter Fehler".

Das Problem ist, dass ich beim Compilieren noch nicht weiss, welche Subklasse ich verwenden werde.

Momentan ist es etwa so implementiert:
ta -> Basisklasse
tb,tc -> Subklassen von ta, die die abstrakte, virtuelle Methode solve implementieren
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button1Click(Sender: TObject);
var b :tb;
       c :tc;
begin
  case index of
    0: begin b:= tb.Create; b.solve; end;
    1: begin c:= tc.Create; c.solve; end;
  end;
end;

Das muss aber irgendwie eleganter gehen. Ich will wie gesagt zur Laufzeit bestimmen, von welcher Subklasse ich eine Instanz bilde, mit der ich dann weiterarbeite.
Die jetzige Lösung ist viel zu sehr ein Hack und wirklich unschön, vor allem wenn man noch mehr Code als bloss das solve hat.

Mein Versuch geht leider auch nicht:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
var a :^TClass;
begin
  a:=TSubKlasse;
  a^:=TSubKlasse.create;
  a.solve;
end;

Ich versuche im Prinzip, eine Referenz auf eine Klasse anzulegen, der ich dann eine Klasse als Typ zuweise und davon möchte ich dann eine Instanz erzeugen. Wahrscheinlich kann Delphi sowas gar nicht, ist eher so eine Art dynamische Kompilierung a la ObjectiveC. Wenn ich mich recht erinnere, habe ich das aber auch in Java schon mal gemacht.

Kann mir da jemand weiterhelfen? Danke!!!

Code-Tags hinzugefügt. Tino
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 24.06.02 13:37 
hi!

Ich habe dein Problem nicht völlig erfassen können, aber vielleicht kann ich dir trotzdem ein wenig weiterhelfen.

Delphi ist in der Lage, dynamisch mit Klassentypen zu arbeiten. Schaue mal in der Hilfe unter "Klassenreferenzen".

Zitat:

Wenn ich so was in der Art tue:

Klasse A
Klasse B (abgeleitet von A)
Klasse C (abgeleitet von A)

Hauptprogramm bei Startbuttonklick:
Var x :A;
Begin
x:=B.create; (B ist aus der Auswahlliste entnommen, könnte auch C sein)
x.solve;
End;

Dann ruft er die Methode solve aus der Klasse A auf und beschwert sich mit "abstrakter Fehler".


Das tritt genau dann auf, wenn die Methode solve eben noch nicht realisiert worden ist, stattdessen wird eben die abstrakte Methode aufgerufen.

Überprüfe den Code noch einmal genau. In B muss die Methode "solve" mit dem Zusatz "override;" deklariert werden.

Cu,
Udontknow
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 24.06.02 13:47 
Jetzt habe ich es (glaube ich) verstanden!

Kreiere einfach eine TClassList! Diese bestückst du dann bei Programmstart mit deinen Klassen.

ausblenden Quelltext
1:
2:
3:
4:
ClassList.Add(MyClass1);
ClassList.Add(MyClass2);
ClassList.Add(B);
ClassList.Add(C);

usw.

Dann musst du nur die ComboBox mit den Einträgen der Classlist füllen.

Die Erstellung läuft dann eben so:

ausblenden Quelltext
1:
MyObject:=ClassList[MyCombobox.ItemIndex].Create;					

Cu,
Udontknow
combatman Threadstarter
Hält's aus hier
Beiträge: 13



BeitragVerfasst: Mo 24.06.02 16:51 
Titel: Danke!
Sorry, war wirklich etwas kompliziert geschrieben. Vielen Dank für die schnelle Hilfe.
Mein Problem war vor allem das vergessene override und natürlich kannte ich die TClassList nicht.

Gruß,
Dirk
Eisenherz
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48



BeitragVerfasst: Mo 24.06.02 18:07 
Hi combatman,

ich will Dich noch auf einen kleinen Fallstrick aufmerksam machen.

Der Konstruktor Create von TObject ist nicht virtuell. Sollte einer Deiner abgeleiteten Klassen einen eigenen Konstruktor Create implementieren, dann wird dieser durch
ausblenden Quelltext
1:
MyObject:=ClassList[MyCombobox.ItemIndex].Create;					

nicht durchlaufen.

_________________
aloa Eisenherz