Einzelnen Beitrag anzeigen

Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#2

Re: Hide-Methode von TInplaceEdit überschreiben

  Alt 28. Jan 2007, 12:02
Zitat von DevilsCamp:
Ich versuche die Hide-Methode von TInplaceEdit zu überschreiben um dem Benutzer die Möglichkeit zu geben zu reagieren, wenn der Editor versteckt wird.
Leider scheitern meine Versuche dahingehend, dass meine selbstgeschriebene Methode einfach nicht ins Programm compiliert werden will

Was mache ich falsch?
Hi, wie sieht denn da die Fehlermeldung aus?
Also so wie Du den Code im Moment stehen hast, sollte das eigentlich kein Problem beim kompilieren geben. Das eigentliche Problem (vielleicht meinst Du auch nur das) sollte darin liegen, dass deine Prozedur hide niemals aufgerufen werden wird.

Wenn Du das meinst, dann würde ich dich bitten das entsprechend in deinem Beitrag zu ändern, denn "rein-kompilieren" ist imho doch etwas anderes.

Um hier zu verstehen, warum es zwar "rein-kompiliert" wird, aber dennoch nie aufgerufen, muss man sich ein wenig damit beschäftigen, wie das überschreiben von Funktionen funktioniert. An sich findet man hier in den meisten Programmiersprachen zwei Möglichkeiten, teilweise implizit, teilweise explizit, man kann Methoden immer verdecken oder überschreiben.
In Delphi ist wichtig, wie die Methoden einer Klasse deklariert werden. Eine Methode kann ohne weitere Direktiven deklariert werden oder als dynamic bzw. virtual (die anderen Direktiven sind hier erstmal nicht wichtig).
Wird eine Methode virtuell oder dynamisch markiert, so findet hier eine dynamische Bindung in der Klasse statt. Das heißt, dass die Klasse die Adresse der Methode erst beim Aufruf ermittelt. Dazu gibt es eine Art Tabelle, in der die Adressen der Methoden drin stehen. Der eigentliche Aufruf der Methode führt also zu dieser Tabelle und von dort zur eigentlichen Adresse. Das ganze nennt man dann Indirektion. Hast Du eine solche Tabelle, so kannst Du hier die Adresse auch einfach verändern. Dabei ist es sogar möglich, dass Du für jede Ebene der Hierachie eine eigene Sprungadresse speicherst. Aber das ist hier erstmal nicht weiter wichtig. Wichtig ist, alle Methoden die dynamic oder virtual sind können überschrieben (Direktive override) werden. Hier wird wirklich die Adresse überschrieben und immer die neue Methode aufgerufen.
Ist keine Direktive angegeben (bei Hide in der Klasse TInPlaceEdit der Fall), so wird die Methode statisch gebunden. Beim statischen Binden wird eine feste Adresse für die Klasse gespeichert. Delphi weiß dann, dass die Adresse immer gleich ist und benötigt entsprechende keine Indirektion. Das spart einfach Zeit! Du hast vielleicht schon häufiger gehört, dass C sehr schnellen Code erzeugt, das liegt einfach schon daran, dass es hier eben weder Klassen noch Indirektionen gibt. Sind alle Adressen statisch, erreicht man hier schon das Optimum an Zeit für den Aufruf. Der Nachteil liegt dafür dann aber im fehlenden Komfort, benötigt man etwas wie Indirektionen, muss man das selbst Programmieren (sehr fehleranfällig).
Ja, eine statisch gebundene Methode kann nur verdeckt werden, überschreiben ist nicht möglich.

Doch was heißt verdecken? Das siehst Du ganz schön in deinem Programm. Du hast eine Klasse TMyInplaceEdit, die von TInPlaceEdit erbt. Beide führen eine Methode Hide, wobei TMyInplaceEdit die Methode des Vorgängers verdeckt. In beiden Fällen wird die Methode Hide statisch gebunden. Wie gesagt, die Methode bleibt erhalten, wird nur durch TMyInplaceEdit verdeckt. Welche der beiden Methoden jetzt aufgerufen wird hängt nur davon ab, von welchem Typ der Aufrufer ist. Ein TMyInplaceEdit kann ja entweder als TMyInplaceEdit behandelt werden (deine Methode wird aufgerufen) oder als TInPlaceEdit (die ursprüngliche Methode wird aufgerufen).
Dein CreateEditor gibt ein TInplaceEdit zurück und genau hier liegt dann das Problem. Sobald Du die Instanz von TMyInPlaceEdit als TInPlaceEdit behandelst (was natürlich völlig ok ist!) wird die statische Bindung von Hide der Klasse TInPlaceEdit verwendet.

Delphi-Quellcode:
var editor: TInPlaceEdit;
    myEditor : TMyInPlaceEdit;
begin
  editor := TMyInPlaceEdit.Create(..);
  editor.hide; // ruft die ursprüngliche Methode auf

  myEditor := TMyInPlaceEdit(editor);
  myEditor.hide; // erwartete, neue Methode wird aufgerufen
end;
So, hoffe es ist halbwegs klar was ich meine. Hier gibt es natürlich Situationen, wo Du sehr sehr sehr viel lieber ein TInPlaceEdit verwenden würdest (oder auch gar nicht anders kannst), aber trotzdem diese Benachrichtung benötigst. Und was soll ich sagen, da hast Du dann ein typisches Delphi Problem. Hier werden Methoden eben standardmässig auf hohe Perfomance optimiert, nicht auf OOP/Vererbung. Um hier dennoch über den Aufruf von hide informiert zu werden, solltest Du einfach mal schauen, ob Du direkt auf eine Botschaft für das Hide reagieren kannst oder sogar einen Hook benutzen musst. Such da einfach mal nach.

Gruß Der Unwissende
  Mit Zitat antworten Zitat