Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt (https://www.delphipraxis.net/165873-class-procedure-aufrufen-wenn-klasse-zur-designzeit-noch-nicht-bekannt.html)

hyype 19. Jan 2012 13:17

class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
hallo

ich habe mehrere klassen, welche eine class function get_irgendwas haben, die aber bei allen was anderes macht!
diese instanziere ich, nutze ihre funktionalität und gebe sie frei.

und nun möchte ich mir während dieses prozesses eine klasse von denen merken (aber nicht das objekt, was eine instanz der klasse darstellt, weil das ist freigegeben, sondern die klasse halt) und von dieser klasse die get_irgendwas methode aufrufen.

wenn meine klasse beispielsweise TTestklasse heißt
bekäme ich bei self.classname 'TTestklasse' zurück
und bei self.classtype TTestklasse vom typ TClass

ich möchte nun TTestklasse.get_irgendwas aufrufen.
das macht der compiler leider nicht mit, logisch.

der compiler prüft, ob die vorm punkt stehende klasse die methode überhaupt hat. da die vorm . stehende klasse zur designzeit noch nicht feststeht, kann er das nicht mit sicherheit sagen. ICH kann es aber mit sicherheit sagen!

mir ist schon klar, dass ich nicht zur laufzeit delphi-code erzeugen kann, der dann compiliert und ausgeführt wird, was ja von der sache her das ist, was ich möchte..

ich möchte keine funktion schreiben a la
Delphi-Quellcode:
if s = 'TTestklasse' then
  result := TTestklasse.get_irgendwas;
hier mal ein wenig code, der so nicht funktioniert, aber der evtl veranschaulicht, was ich will:
Delphi-Quellcode:
var my_class:tclass;
    t1 : ttestklasse1;
    t2 : ttestklasse2;
begin
  t1 := ttestklasse1.create;
  t2 := ttestklasse2.create;
...
  my_class := t1.classtype;
  //oder eben t2.classtype
  //das soll mich hier nicht interessieren sondern erst ganz am ende
...
freeandnil(t1);
freeandnil(t2);
...
showmessage(my_class.get_irgendwas);
end;
die methode get_irgendwas würde der compiler jetzt in TClass suchen, nicht finden und rummeckern. er soll aber die methode der klasse ausführen, deren typ in my_class gekapselt ist

das MUSS doch irgendwie gehen!!!

DANKE euch schonmal

Uwe Raabe 19. Jan 2012 13:28

AW: class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
Ohne große Verrenkungen (Stichwort: RTTI) geht das nur, wenn deine Klassen alle von einer Basisklasse abgeleitet sind, die bereits die Klassenmethode get_irgendwas virtuell deklariert.

DeddyH 19. Jan 2012 13:31

AW: class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
Sofern ich das richtig verstanden habe fallen mir spontan 2 Möglichkeiten ein (wobei ich bei beiden nicht sicher bin, ob das auch mit Klassenmethoden funktioniert, einen Versuch ist es aber wert):
- Eine gemeinsame Basisklasse, die die Klassenmethode abstrakt einführt. Diese Methode wird dann in den abgeleiteten Klassen überschrieben, der Variablentyp ist dann der der Basisklasse.
- Ein Interface mit dieser Methode, das von den Klassen implementiert wird. Variablentyp wäre dann das Interface.

[edit] Wo war der rote Kasten? [/edit]

himitsu 19. Jan 2012 13:38

AW: class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
@DeddyH: Ja, Klassenmethoden können auch virtuell sein.

Ein Interface geht natürlich nicht mit Klassenmethoden (ohne Objekt dahinter), da dieses Interface ja ein instanziiertes Objekt beötigt.

hyype 19. Jan 2012 14:24

AW: class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
vielen dank für eure antworten.
interface geht wie schon gesagt wurde nicht mit class procedures/functions, hatte ich auch probiert
basisklasse mit abstrakter methode ist z.z. auch meine lösung für das problem ;)
ich bin mir aber nicht sicher, ob das nicht irgendwann nachteilig sein könnte
so sieht es atm aus:
Delphi-Quellcode:
type

  TFBase = class(TObject)
  public
    class function Get_irgendwas: String; virtual; abstract;
  end;

  TF1 = class(TFBase)
    class function Get_irgendwas: String; override;
  end;

  TF2 = class(TFBase)
    class function Get_irgendwas: String; override;
  end;
Delphi-Quellcode:
procedure TForm1.Button8Click(Sender: TObject);
var
  helper: TObject;
  z1: TF1;
  z2: TF2;
begin
  z1 := TF1.Create;
  z2 := TF2.Create;

  helper:= z1;

  FreeAndNil(z1);
  FreeAndNil(z2);

  Writeln((helper as TFBase).Get_irgendwas)
end;

{ TF2 }
class function TF2.Get_irgendwas: String;
begin
  result := 'tf2';
end;

{ TF1 }
class function TF1.Get_irgendwas: String;
begin
  result := 'tf1';
end;
jetzt noch eine frage: ich lasse die tobject-variable helper auf das objekt im speicher zeigen, auf das z1 zeigt. danach gebe ich z1 frei. dadurch müsste doch helper erstmal auf nix zeigen, aber auch nicht nil sein. dann caste ich helper als tfbase und er ruft die tf1.get_irgendwas methode auf.
da würde ich mich dafür interessieren, woher er noch weiß, dass es ein tf1-objekt ist und ob es eine schönere möglichkeit gibt, so ein objekt zu erzeugen ^^

einbeliebigername 19. Jan 2012 14:58

AW: class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
Zitat:

Zitat von hyype (Beitrag 1146707)
da würde ich mich dafür interessieren, woher er noch weiß, dass es ein tf1-objekt ist und ob es eine schönere möglichkeit gibt, so ein objekt zu erzeugen ^^

Da hast du nur Glück, das zwischen
Delphi-Quellcode:
FreeAndNil(z1);
und
Delphi-Quellcode:
Writeln((helper as TFBase).Get_irgendwas)
der Speicherbereich, wo z1 mal lag, nicht überschrieben wird.
Besser so:
Delphi-Quellcode:
type
  TFBaseClass= class of TFBase;

...

var
  helper: TFBaseClass;

...

  helper:= TFBaseClass(z1.ClassType);

...

  Writeln(helper.Get_irgendwas);
Einbeliebigername.

mjustin 19. Jan 2012 15:10

AW: class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
Zitat:

Zitat von hyype (Beitrag 1146707)
Delphi-Quellcode:
    class function Get_irgendwas: String; virtual; abstract;

abstract habe ich früher auch gelegentlich verwendet - aber um die kryptische Fehlermeldung

"Abstrakter Fehler"

zu vermeiden, schreibe ich entweder eine Defaultimplementierung oder werfe eine aussagekräftige Exception.

Delphi-Quellcode:
class function TMyClass.Get_irgendwas: String;
begin
  raise Exception.Create('Bitte nicht vergessen, dass abstrakte Methoden überschrieben werden müssen. Danke!');
end;

himitsu 19. Jan 2012 17:37

AW: class procedure aufrufen, wenn klasse zur designzeit noch nicht bekannt
 
Wenn Emba die Delphi-Referenz durchsuchenAbstractErrorProc um die neue RTTI erweitern würde, indem dort der RTTI-Eintrag dieser Methode übergeben würde, dann gäbe es eine ideale Lösung.

Auch früher hätte man zumindestens den Klassennamen und den Index der VMT ausgeben können, denn diese Daten sind immer bekannt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:39 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