AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Verweis auf Interface-Instanz weitergeben - ist das erlaubt?
Thema durchsuchen
Ansicht
Themen-Optionen

Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

Ein Thema von Bodenseematze · begonnen am 27. Feb 2024 · letzter Beitrag vom 1. Mär 2024
Antwort Antwort
Bodenseematze

Registriert seit: 10. Jul 2023
69 Beiträge
 
#1

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 27. Feb 2024, 12:12
Wenn du also ein solches Objekt in einer Interfacereferenz speicherst und das Objekt freigegeben wird, zeigt die Interfacereferenz auf ein ungültiges Objekt.
Das ist mir schon klar - das sollte auch nicht passieren...


Allerdings ist sie deshalb nicht 0, was genau das Problem an der Stelle ist. Deshalb muss man dort aufpassen, was man tut.
Die Klassen-Instanz, auf die der Interface-Verweis zeigt, wird als letztes abgebaut --> das sollte eigentlich passen
Mir kommt es so vor, als ob durch das Verlassen der Get-Methode der Interface-Zeiger abgeräumt und auf nil gesetzt wird...

Das kannst du nicht im Debugger nachstellen und dort prüfen?
Hmm, ich habe den oben geposteten Beispielcode mal vervollständigt und als Mini-Delphi-Projekt angelegt.
Da muss noch ein anderes (für mich gerade nicht sichtbares) Problem bestehen - da kommt jetzt bei mir beim Start im Debugger eine Access-Violation;
allerdings ohne, dass ich den Call-Stack sehen kann

Ich habe das Projekt mal als .zip angehängt...
Angehängte Dateien
Dateityp: zip IfTest.zip (6,5 KB, 1x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.909 Beiträge
 
Delphi 12 Athens
 
#2

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 27. Feb 2024, 13:30
Da muss noch ein anderes (für mich gerade nicht sichtbares) Problem bestehen - da kommt jetzt bei mir beim Start im Debugger eine Access-Violation;
allerdings ohne, dass ich den Call-Stack sehen kann
Delphi 7 halt...
In einer aktuelleren Version (hier die Community Edition) siehst du die Ursache:
Screenshot 2024-02-27 131554.png

Ursache:
Delphi-Quellcode:
constructor TMyMainForm.CreateMe( owner_ : TComponent );
begin
   inherited Create( owner_ );
Besser:
Delphi-Quellcode:
constructor TMyMainForm.CreateMe( owner_ : TComponent );
begin
   inherited;
Wenn sich die Methodensignatur des geerbten Aufrufs nicht ändert, sollte man nur inherited schreiben. An anderer Stelle fehlte das inherited, so dass die Initialisierung des Formulars fehlte.

Grundregel:
Wenn es irgendwie anders geht, sollte man Konstruktoren NIE NIE NIE anders als Create nennen. Das ist wirklich nur eine Notlösung (und den Sinn verstehe ich hier nicht, da es zumindest in dem gekürzten Beispiel ohne viel einfacher geht).

Ein weiterer Fehler:
FormCreate und btOKClick waren unter public statt unter published (weshalb diese Eventhandler automatisch direkt nach der Klassendeklaration erzeugt werden, wo sie published sind, auch ohne das Wort). Unter public können sie aber nicht gefunden werden.

Ansonsten kann ich keine Probleme feststellen, auch nicht mit Delphi 7. Was muss ich tun?

Gibt es eigentlich einen Unterschied (im Ergebnis-Zeiger) bei den folgenden Methoden, die Variable myIf zu setzen (Voraussetzung ist natürlich, dass MyClassInst das Interface implmentiert)?
In aktuellen Delphiversionen gibt es da keinen Unterschied mehr. In älteren Versionen konnte man nicht einfach auf das Interface casten. Ich weiß nicht mehr, wann das geändert wurde.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.338 Beiträge
 
Delphi 12 Athens
 
#3

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 27. Feb 2024, 13:58
Ja, seit einer ganzen Weile existiert ein virtuelles Interface, welches TInterface nach TObject casten kann, z.B. einfach mit AS. (seit mindestens D2009/XE)

Ansonsten implementiert TComponent schon seit vielen Jahren auch noch ein IInterfaceComponentReference, welches eine Methode GetComponent bietet.
Delphi-Referenz durchsuchenIInterfaceComponentReference.GetComponent
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
69 Beiträge
 
#4

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 27. Feb 2024, 14:31
Ursache:
Delphi-Quellcode:
constructor TMyMainForm.CreateMe( owner_ : TComponent );
begin
   inherited Create( owner_ );
Besser:
Delphi-Quellcode:
constructor TMyMainForm.CreateMe( owner_ : TComponent );
begin
   inherited;
Wenn sich die Methodensignatur des geerbten Aufrufs nicht ändert, sollte man nur inherited schreiben. An anderer Stelle fehlte das inherited, so dass die Initialisierung des Formulars fehlte.
Du hast natürlich Recht - aber das war nicht der Fehler; das war nur temporär geändert (und nicht wieder zurück geändert), weil ich damit gespielt hatte, die MyMainForm testweise nur von TForm abzuleiten (und die hat ja kein CreateMe-Konstruktor) - dann kam die Access Violation "später"...

Grundregel:
Wenn es irgendwie anders geht, sollte man Konstruktoren NIE NIE NIE anders als Create nennen. Das ist wirklich nur eine Notlösung (und den Sinn verstehe ich hier nicht, da es zumindest in dem gekürzten Beispiel ohne viel einfacher geht).
Der Grund dafür ist, dass ich den Konstruktor virtuell brauche, damit in abgeleiteten Klassen deren Konstruktor aufgerufen wird...
...und ich kann doch den Standard "Create"-Konstruktor nicht als virtuell überschreiben / neu schreiben, da dieser nicht virtuell ist - oder geht das irgendwie?
Deswegen der neue Konstruktor "CreateMe" in TMyBaseForm und eine "Umlenkumg" auf diesen im Standard-Konstruktor "Create"...
Oder verstehe ich da was falsch?

Was aber tatsächlich gefehlt hatte, war das inherited in TMyBaseForm auf den Basis-Konstruktor von TForm:
Delphi-Quellcode:
constructor TMyBaseForm.CreateMe( owner_ : TComponent );
var
   ifTestImplMy : ITestImpl;
begin
   inherited Create( owner_ );

   _ifTestImpl := nil;
   if ( Assigned(owner_) and
        Supports(owner_, ITestImpl, ifTestImplMy) ) then begin
      SetIfTestImpl( ifTestImplMy );
   end;
end;
Ein weiterer Fehler:
FormCreate und btOKClick waren unter public statt unter published (weshalb diese Eventhandler automatisch direkt nach der Klassendeklaration erzeugt werden, wo sie published sind, auch ohne das Wort). Unter public können sie aber nicht gefunden werden.
Das verstehe ich nicht so richtig - kannst Du da nochmal anders/genauer erklären?
Ich habe den Sinn vom "published" sowieso noch nie so richtig verstanden...

Ansonsten kann ich keine Probleme feststellen, auch nicht mit Delphi 7. Was muss ich tun?
Ich leider auch nicht - in dem Beispiel-Projekt funktioniert die Auswertung des Interfaces
Also muss im realen Programm noch irgendwas anders / komplizierter sein - ich muss da nochmal genauer schauen...


Ansonsten implementiert TComponent schon seit vielen Jahren auch noch ein IInterfaceComponentReference, welches eine Methode GetComponent bietet.
Delphi-Referenz durchsuchenIInterfaceComponentReference.GetComponent
Sehr interessant - kannte ich noch nicht
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.338 Beiträge
 
Delphi 12 Athens
 
#5

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 27. Feb 2024, 15:00
Zitat:
und ich kann doch den Standard "Create"-Konstruktor nicht als virtuell überschreiben / neu schreiben, da dieser nicht virtuell ist - oder geht das irgendwie?
Warum nicht?

siehe TObject.Create und TComponent.Create

Ob man beim "Verdecken" micht einem neuen Contructor noch ein reintroduce benötigt, das mehrkt man dann schon.
Bei gleicher Signatur (Parameter) geht nur verdecken. Und ansonsten muß man noch überlegen, ob ein overload benötigt wird, um alternativ auch die Constructoren der Vorfahren aufrufen zu können.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
69 Beiträge
 
#6

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 27. Feb 2024, 16:28
Zitat:
und ich kann doch den Standard "Create"-Konstruktor nicht als virtuell überschreiben / neu schreiben, da dieser nicht virtuell ist - oder geht das irgendwie?
Warum nicht?
Du hast natürlich wieder mal Recht.
Keine Ahnung mehr, warum ich das in meinem Projekt umbenannt hatte.
Irgendwas ging nicht - war's vielleicht das mit dem "overload", was nicht ging ?

Im Testprojekt geht es auf jeden Fall problemlos so:
constructor Create( owner_ : TComponent ); virtual;

EDIT:
und mit überladenen Konstruktor geht's z.B. so:
Delphi-Quellcode:
constructor Create( owner_ : TComponent ); overload; override;
constructor Create( owner_ : TComponent;
                    const sTestName_ : String ); reintroduce; overload; virtual;
Ich habe das Testprogramm nochmals erweitert und etwas komplizierter gemacht (um es mehr Richtung Realität zu bringen).
Nur funktioniert da alles wie gewünscht - sehr seltsam!

Ich habe das Projekt mal wieder angehängt...
Angehängte Dateien
Dateityp: zip IfTest.zip (225,4 KB, 3x aufgerufen)

Geändert von Bodenseematze (27. Feb 2024 um 16:44 Uhr)
  Mit Zitat antworten Zitat
Bodenseematze

Registriert seit: 10. Jul 2023
69 Beiträge
 
#7

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 1. Mär 2024, 13:42
Zitat:
und ich kann doch den Standard "Create"-Konstruktor nicht als virtuell überschreiben / neu schreiben, da dieser nicht virtuell ist - oder geht das irgendwie?
Warum nicht?
Du hast natürlich wieder mal Recht.
Keine Ahnung mehr, warum ich das in meinem Projekt umbenannt hatte.
Irgendwas ging nicht - war's vielleicht das mit dem "overload", was nicht ging ?
Jetzt weiß ich wieder, was nicht ging bzw. was das Problem mit den Konstruktoren mit Namen "Create" ist.
Ich wollte jetzt im tatsächlichen Projekt die Konstruktoren mit anderem Namen alle auf "Create" zurück ändern.
Nachdem ich das gemacht habe, war das erste Ergebnis in der BaseForm-Klasse so:
Delphi-Quellcode:
constructor Create( compOwner_ : TComponent;
                    const posInitial_ : TMyPos;
                    bIsFormSingleton_ : Boolean;
                    iScalePercentage_ : Integer = -1 ); overload; virtual;
constructor Create( compOwner_ : TComponent;
                    bIsFormSingleton_ : Boolean;
                    iScalePercentage_ : Integer = -1 ); overload; virtual;
constructor Create( compOwner_ : TComponent;
                    iScalePercentage_ : Integer ); overload; virtual;

// aus TCustomForm:
constructor Create( compOwner_ : TComponent ); overload; override;
Das lässt sich so nicht übersetzen - hier meckert der Compiler, bei den ersten drei Konstruktoren
(also die mit zusätzlichen Parametern, die es in den Basisklassen gar nicht gibt):
Code:
Method 'Create' hides virtual method of base type 'TCustomForm'


Also muss ich das so machen:
Delphi-Quellcode:
constructor Create( compOwner_ : TComponent;
                    const posInitial_ : TMyPos;
                    bIsFormSingleton_ : Boolean;
                    iScalePercentage_ : Integer = -1 ); reintroduce; overload; virtual;
constructor Create( compOwner_ : TComponent;
                    bIsFormSingleton_ : Boolean;
                    iScalePercentage_ : Integer = -1 ); reintroduce; overload; virtual;
constructor Create( compOwner_ : TComponent;
                    iScalePercentage_ : Integer ); reintroduce; overload; virtual;

// aus TCustomForm:
constructor Create( compOwner_ : TComponent ); overload; override;
Und dann habe ich in der BaseFormMain (abgeleitet von BaseForm) als einzigen Konstruktor folgendes definiert:
Delphi-Quellcode:
constructor Create( compOwner_ : TComponent;
                    const posInitial_ : TMyPos;
                    bIsFormSingleton_ : Boolean;
                    iScalePercentage_ : Integer = -1 ); override;
Im BaseFormMain-Konstruktor steht dann am Anfang:
inherited; Das ruft auch (richtigerweise) den Konstruktor mit vier Parametern in BaseForm auf.

Die BaseForm-Konstruktoren mit weniger Parametern rufen alle den Konstruktor mit vier Parametern auf;
in diesem steht dann noch:
inherited Create( compOwner_ ); Gedacht ist, dass er den Konstruktor in TCustomForm aufruft.
Macht er aber nicht - stattdessen wird (erneut) der Konstruktor in BaseFormMain aufgerufen.

Also ein prima Endlos-Rekursionsschleife gebastelt

Nur ist mir nicht klar, warum das passiert...
...und wie ich ihn dazu bringen könnte, mit dem o.a. inherited den korrekten Konstruktor in TCustomForm aufzurufen
(ohne die Konstruktoren wieder alle umzubenennen)...

EDIT: Hier noch der vollständige Stack-Aufruf:
Durch Application.CreateForm mit der Implementierung der MainForm (abgeleitet von BaseFormMain) wird folgendes aufgerufen:
  1. in der Klasse BaseForm der überschriebene Konstruktor mit einem Parameter;
  2. der wiederum ruft direkt den Konstruktor mit vier Parametern auf --> hier wird der überschriebene Konstruktor in der MainForm-Instanz aufgerufen,
  3. der wiederum über inherited den (einzigen) Konstruktor mit vier Parametern in BaseFormMain aufruft,
  4. der wiederum über inherited den Konstruktor mit vier Parametern in BaseForm aufruft;
  5. und der ruft dann über inherited wieder seinen (!) Konstruktor mit einem Parameter auf...
  6. ...usw. (jetzt geht's wieder bei 1 los)
Die Frage ist also immer noch: warum wird trotz "inherited"-Aufruf der eigene Konstruktor aufgerufen?

Geändert von Bodenseematze ( 1. Mär 2024 um 14:17 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.338 Beiträge
 
Delphi 12 Athens
 
#8

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 1. Mär 2024, 14:44
Zitat:
Das lässt sich so nicht übersetzen
Wie jetzt.
Meckert Heult der nur rum (Info oder Warning), oder stoppt er wirklich die Arbeit (Error oder Fatal) ?

Zitat:
Method 'Create' hides virtual method of base type 'TCustomForm'
Du kannst versuchen das "normale" Create nach oben zu verschieben, aber oft bleibt nichts Übrig, als diese "unsinnige" Meldung via Reintroduce loszuwerden.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.909 Beiträge
 
Delphi 12 Athens
 
#9

AW: Verweis auf Interface-Instanz weitergeben - ist das erlaubt?

  Alt 1. Mär 2024, 15:41
Die Frage ist also immer noch: warum wird trotz "inherited"-Aufruf der eigene Konstruktor aufgerufen?
Entferne das override. Damit überschreibst du den geerbten Konstruktor, so dass dieser dann aufgerufen wird.

Die Konstruktion ist aber seltsam. Warum ruft der überschriebene Konstruktor mit einem Parameter den mit 4 Parametern auf, wenn der doch ohnehin wieder den mit einem Parameter aufruft? Ohne zu wissen was darin passiert, lässt sich dazu aber nicht viel sagen. Das kann man sicher anders lösen.

Eine Möglichkeit wäre, die Initialisierung aus dem Konstruktor auszulagern, so dass die Konstruktoren sich nicht mehr so viel gegenseitig aufrufen müssen. Im Konstruktor sollte im Normalfall auch nur die reine Initialisierung passieren, keine Ladevorgänge oder weitergehende Aktionen.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:47 Uhr.
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