OOP Destructor wird nicht aufgerufen..

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1620
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

OOP Destructor wird nicht aufgerufen..

Beitrag von corpsman »

Servus,

Ich habe ein Problem und auch schon die Lösung. Nur verstehe ich nicht ganz warum das ganze ein Problem war.

Es geht um die Ausgabe des Programms im Anhang

Richtig ist
odroid@odroid:~/Temp/oop_murks$ ./project1
Ta.create
Tb.create
Tb.destroy
Ta.destroy
Mit dem "Fehler" ist die Ausgabe aber nur
odroid@odroid:~/Temp/oop_murks$ ./project1
Ta.create
Tb.create
=> die Destructoren werden nicht aufgerufen.

Einziger Unterschied bei beiden Compile Vorgängen war

Code: Alles auswählen

 
Type
 
  { Ta }
 
  Ta = Class
  private
  public
    Constructor create; virtual;
    Destructor destroy; override; // So funktionierts
//    Destructor destroy; virtual; reintroduce; // So funktionierts nicht
  End;
 
  { tb }
 
  tb = Class(ta)
  private
  public
    Constructor create; override;
    Destructor destroy; override;
  End;
 
 
Freigegeben wird das Objekt mittels tb.free;

Meines Erachtens muss free das destroy aufrufen, und das müsste es machen, egal ob ich das so komisch neu definiert habe oder nicht.

Habt ihr eine passende Erklärung ?
Dateianhänge
oop_murks.zip
kompletter Source
(2.5 KiB) 80-mal heruntergeladen
--
Just try it

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2809
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von m.fuchs »

Wenn .Free aufgerufen wird, ruft es seinerseits .Destroy auf. .Free ist aber eine Methode von TObject. Um das .Destroy deiner Klasse aufzurufen, muss dieses als override deklariert sein.

Durch das reintroduce wird das sorgst du dafür, dass wieder das .Destroy von TObject aufgerufen wird. Denn damit wird das originale .Destroy verborgen. Aber natürlich nur für deine Klasse, nicht für TObject.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1620
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von corpsman »

Also laut FPC-Reference Manual Seite 197.

Ersetzt das reintroduce das destroy in der VMT (was auch das ist, was ich vermutet hatte, aber wohl doch nicht richtig ist).

Laut BNF eine Seite davor dürfte man "virtual reintroduce" aber gar nicht schreiben, dort steht, dass man mittels reintroduce die virtuelle Methode überschreiben kann und den Status "virtuel" damit aufhebt. Überschreiben und virtuell erhalten macht man dann mittels override.
-\
-/ ich bleibe verwirrt.
--
Just try it

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2809
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von m.fuchs »

Hm, ich habe mich mal in der Online-Version vom Manual umgesehen:
If the virtual method should really be replaced with a method with the same name, then the reintroduce keyword can be used
Soweit so gut, nun aber folgt.
To be able to do this, the compiler keeps - per class type - a table with virtual methods: the VMT (Virtual Method Table). This is simply a table with pointers to each of the virtual methods: each virtual method has its fixed location in this table (an index). The compiler uses this table to look up the actual method that must be used at runtime. When a descendent object overrides a method, the entry of the parent method is overwritten in the VMT.
Das würde deiner Erwartung entsprechen, ABER: Ich meine, dass dieser Absatz sich nicht auf reintroduce bezieht, sondern auf die Thematik virtuelle Methoden im Allgemeinen. Ist natürlich etwas unübersichtlich.

Hier ist es deutlicher beschrieben, was reintroduce macht: http://wiki.freepascal.org/Reintroduce/de
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2809
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von m.fuchs »

Ach ja, dazu noch:
corpsman hat geschrieben:Laut BNF eine Seite davor dürfte man "virtual reintroduce" aber gar nicht schreiben, dort steht, dass man mittels reintroduce die virtuelle Methode überschreiben kann und den Status "virtuel" damit aufhebt. Überschreiben und virtuell erhalten macht man dann mittels override.
Du entfernst den virtual-Status mit reintroduce, aber setzt einen neuen für deine eingeführte Methode.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1620
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von corpsman »

So wie du es schreibst, ist es wie ich es interpretiere. Der Aufruf tb.free müsste also definitiv das tb.destroy aufrufen. Dies scheint ja nicht zu geschehen.

Mit BNF meinte ich diese. Nach meinem Verständniss ist "virtual" vor "Reintroduce" damit nicht erlaubt.
--
Just try it

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von mse »

Normalerweise warnt der Compiler, wenn eine geerbte virtuelle Prozedur von einer neuen verdeckt wird. "reintroduce" bezeichnet, dass dies gewollt ist und unterdrückt die Warnung.
"free" ruft "TObject.destroy()" und nicht "ta.destroy()" da "ta.destroy()" den Zusatz "virtual" und nicht "override" hat. "virtual" bedeutet "procedure die überschrieben werden kann", "override" bedeutet "procedure die eine Kette geerbter Prozeduren überschreibt". "virtual" startet also eine neue Kette (wie schon m.fuchs geschrieben hat). Darum sind "TObject.destroy()" und "ta.destroy()" unabhängig.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1620
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von corpsman »

Damit wird aus meiner Sicht das "reintroduce" aber zu einem Problem.

Da ich ja beim object.free im Sinne der OOP schon erwarte, dass der Richtige Destroy aufgerufen wird.

Hat jemand ein Sinnvolles Besipiel für die Nutzung von Reintroduce, damit ich mir das merken kann ?
--
Just try it

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von mse »

Überschreiben des virtuellen "TComponent.Create()", z.B.
https://gitlab.com/mseide-msegui/mseide ... lepage.pas
Wie gesagt, "reintroduce" dient lediglich dazu die Warnung zu unterdrücken (AFAIK).

dezipaitor
Beiträge: 12
Registriert: Sa 10. Nov 2007, 12:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von dezipaitor »


Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2809
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von m.fuchs »

corpsman hat geschrieben:So wie du es schreibst, ist es wie ich es interpretiere. Der Aufruf tb.free müsste also definitiv das tb.destroy aufrufen.
Nein, eben nicht. Das ist ja der Sinn von dem reintroduce.
corpsman hat geschrieben:Damit wird aus meiner Sicht das "reintroduce" aber zu einem Problem.
Da ich ja beim object.free im Sinne der OOP schon erwarte, dass der Richtige Destroy aufgerufen wird.
Was ist schon richtig, was ist falsch? Das richtige .Destroy wird aufgerufen. Nämlich das letzte in der Vererbungskette, bevor .Destroy überschrieben und verdeckt wurde.
corpsman hat geschrieben:Hat jemand ein Sinnvolles Besipiel für die Nutzung von Reintroduce, damit ich mir das merken kann ?
Ich habe jetzt mal mein privates und mein Arbeits-Repository durchsucht. An keiner Stelle habe ich reintroduce im Einsatz. Ein Praxisbeispiel will mir auch partout nicht einfallen. Sieht nach einem Sprachfeature aus, was nur sehr selten gebraucht wird.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von Patito »

m.fuchs hat geschrieben: Ich habe jetzt mal mein privates und mein Arbeits-Repository durchsucht. An keiner Stelle habe ich reintroduce im Einsatz. Ein Praxisbeispiel will mir auch partout nicht einfallen. Sieht nach einem Sprachfeature aus, was nur sehr selten gebraucht wird.
Reintroduce ist ein gutes Erkennungsmerkmal für Design-Fehler. Man hat etwas in der Basisklasse implementiert,
und will es jetzt nachträglich verstecken. Statt die Warnung mit reintroduce zu verstecken, hätte man besser versuchen sollen
die Strukturen in Ordnung zu bringen.

Es ist zwar theoretisch interessant zu verstehen wie genau das jetzt genau für Destruktoren intern funktionieren sollte, aber
praktisch hat das alles für guten Code eher keine Bedeutung.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1620
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von corpsman »

Danke patito und m.fuchs irgendwie dachte ich auch schon, wtf mit dem reintroduce. Es als indix für schlechte Softwarearchitektur bzw Design zu nehmen ist da wohl das treffendste. Werde morgen mal schaun, wie viele reintroduce ich so in meinem Code habe (seit diesem Thread definitiv 2 weniger ;) ),
--
Just try it

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von mse »

corpsman hat geschrieben:Danke patito und m.fuchs irgendwie dachte ich auch schon, wtf mit dem reintroduce. Es als indix für schlechte Softwarearchitektur bzw Design zu nehmen ist da wohl das treffendste. Werde morgen mal schaun, wie viele reintroduce ich so in meinem Code habe (seit diesem Thread definitiv 2 weniger ;) ),
Und wie würdest du dann mein Beispiel lösen?

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2809
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: OOP Destructor wird nicht aufgerufen..

Beitrag von m.fuchs »

Das hier: https://gitlab.com/mseide-msegui/mseide ... lepage.pas ?

Warum hast du da überhaupt reintroduce verwendet?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Antworten