Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Abstrakter Fehler bei leerer Prozedur (https://www.delphipraxis.net/178813-abstrakter-fehler-bei-leerer-prozedur.html)

Codehunter 29. Jan 2014 08:06

Delphi-Version: XE4

Abstrakter Fehler bei leerer Prozedur
 
Hallo!

Ich habe ein kleines Verständnisproblemchen mit abstrakter Vererbung. In einer Vorfahrklasse wird eine virtuelle abstrakte Methode (z.B. "Proc1") eingeführt, aber (logischerweise) noch nicht implementiert. In einer zweiten Methode (z.B. "Proc2") dieser Vorfahrklasse wird die abstrakte Methode aufgerufen.

Eine Nachfahrklasse implementiert jetzt zwar "Proc1", fügt aber keinen Code ein da sie "Proc1" eigentlich nicht benötigt. Allerdings wird für die Nachfahrklasse nun im Hauptprogramm die "Proc2" aufgerufen und damit auch indirekt "Proc1". Und RUMMS gibts da einen abstrakten Fehler.

Ich denke mal, der Compiler optimiert die leere Implementierung von "Proc1" in der Nachfahrklasse einfach weg, denn wenn ich darin irgendwelchen Nonsenscode stehen habe funktioniert alles.

Mache ich da jetzt einen konstruktivischen Fehler oder muss ich an der Stelle das "Wegoptimieren" von "Proc1" unterbinden?

Grüße
Cody

jaenicke 29. Jan 2014 08:08

AW: Abstrakter Fehler bei leerer Prozedur
 
Wegoptimiert wird das eigentlich nicht, ich habe da auch nicht immer gleich Code drin.

Dumme Frage, aber das override hast du nicht vergessen, oder?

DeddyH 29. Jan 2014 08:15

AW: Abstrakter Fehler bei leerer Prozedur
 
Gerade unter XE versucht:
Delphi-Quellcode:
type
  TClassA = class
  protected
    procedure Proc1; virtual; abstract;
  public
    procedure Proc2;
  end;

  TClassB = class(TClassA)
  protected
    procedure Proc1; override;
  end;

{ TClassA }

procedure TClassA.Proc2;
begin
  Proc1;
end;

{ TClassB }

procedure TClassB.Proc1;
begin
  inherited;

end;

procedure TFormTest.Button1Click(Sender: TObject);
var
  ClassB: TClassB;
begin
  ClassB := TClassB.Create;
  try
    ClassB.Proc2;
  finally
    ClassB.Free;
  end;
end;
Es passiert zwar nichts (was auch?), aber es gibt auch keinen Fehler.

Popov 29. Jan 2014 08:16

AW: Abstrakter Fehler bei leerer Prozedur
 
Ich hab zwar noch nicht ganz verstanden wie die Zusammenhänge sind, aber das Wegoptimieren kann ich mir schwer vorstellen. Guck dir mal TObject Create oder Destroy an, beide leer, und auf beide wird vermutlich millionenfach über Inherited zugegriffen. Würden leere Prozeduren weg optimiert, würde es ständig krachen.

Ist aber nur meine persönliche Einschätzung. Muss nicht richtig sein.

Auf der anderen Seite, schon die Klasse Schritt für Schritt mit F7 durchlaufen lassen?

Der schöne Günther 29. Jan 2014 08:54

AW: Abstrakter Fehler bei leerer Prozedur
 
Hinweis: "inherited" an sich ist kein Problem wenn die überschriebene Methode der Elternklasse komplett abstrakt ist. Es wird aber ein EAbstractError ausgelöst wenn man den Namen der Methode ausschreibt!

Delphi-Quellcode:
interface

   TBaseClass = class
      public procedure someMethod(); virtual; abstract;
   end;

   TChildClass = class(TBaseClass)
      public procedure someMethod(); override;
   end;

implementation

   procedure TChildClass.someMethod();
   begin
      inherited; // Kein Problem
      inherited someMethod(); // Wirft EAbstractError
   end;

PS: Wegoptimiert wird das ganz sicher nicht. Das kannst du prüfen, ob nach Shift+F9 da noch die blauen Haltepunkte zu sehen sind.

Und: Ich denke eher, du erstellst in Wirklichkeit eine Instanz er Elternklasse mit der noch abstrakten Methode anstatt der erbenden Klasse, oder?

DeddyH 29. Jan 2014 09:46

AW: Abstrakter Fehler bei leerer Prozedur
 
In Delphi 5 wirft auch das inherited alleine einen abstrakten Fehler (obwohl die Klassenvervollständigung es ja selbst eingefügt hat). Ich denke eher, dass tatsächlich das override vergessen wurde wie oben bereits vermutet, dadurch wird die Methode nicht überladen überschrieben, sondern überschrieben verdeckt und somit die abstrakte der Elternklasse aufgerufen.

Codehunter 29. Jan 2014 10:07

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von jaenicke (Beitrag 1245796)
Dumme Frage, aber das override hast du nicht vergessen, oder?

Nein nicht vergessen :-D
Zitat:

Zitat von Der schöne Günther (Beitrag 1245808)
Ich denke eher, du erstellst in Wirklichkeit eine Instanz er Elternklasse mit der noch abstrakten Methode anstatt der erbenden Klasse, oder?

Das stimmt sogar und müsste die beschriebenen Probleme eigentlich erklären. Also habe ich Proc1 in der Vorfahrklasse testweise nicht abstract gemacht sondern nur noch virtual und die leere Prozedur-implementation dort schon angelegt. Auf ein override der leeren Proc1 mit einer weiteren leeren Proc1 in der Nachfahrklasse habe ich dann mal verzichtet. Ansonsten das selbe Konstrukt, wie DeddyH in seinem ersten Beispiel schon so schön darstellt. Resultat: Abstrakter Fehler.

Ich kanns mir nur mit Compileroptimierung erklären, denn während folgender Code den Abstrakten Fehler produziert:
Delphi-Quellcode:
procedure TVorfahrKlasse.Proc1;
begin

end;
liefert folgender Sinnloscode keinen Fehler mehr:
Delphi-Quellcode:
procedure TVorfahrKlasse.Proc1;
var
  bDummy: Boolean;
begin
  bDummy:= TRUE;
end;

Der schöne Günther 29. Jan 2014 10:12

AW: Abstrakter Fehler bei leerer Prozedur
 
Sind denn nach [Shift]+[F9] die blauen Haltepunkte noch da?

Dann mal zum Nachstellen: Wir reden über Delphi XE4 (Updates, Hotfixes?), kompiliert für Win32?

Sir Rufo 29. Jan 2014 10:22

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von Codehunter (Beitrag 1245824)
Ich kanns mir nur mit Compileroptimierung erklären, denn während folgender Code den Abstrakten Fehler produziert:
Delphi-Quellcode:
procedure TVorfahrKlasse.Proc1;
begin

end;
liefert folgender Sinnloscode keinen Fehler mehr:
Delphi-Quellcode:
procedure TVorfahrKlasse.Proc1;
var
  bDummy: Boolean;
begin
  bDummy:= TRUE;
end;

Zeig doch mal den ganzen Code und nicht nur das linke Ohr des Eisbären :)

baumina 29. Jan 2014 10:32

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von Sir Rufo (Beitrag 1245828)
Zeig doch mal den ganzen Code und nicht nur das linke Ohr des Eisbären :)

Erinnert mich an Dalli Klick :-D

jaenicke 29. Jan 2014 11:00

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von Codehunter (Beitrag 1245824)
Das stimmt sogar und müsste die beschriebenen Probleme eigentlich erklären. Also habe ich Proc1 in der Vorfahrklasse testweise nicht abstract gemacht sondern nur noch virtual und die leere Prozedur-implementation dort schon angelegt. [...] Resultat: Abstrakter Fehler.

Wenn du dort irgendwelche abstrakten Methoden drin hast, darfst du die Elternklasse auch nicht direkt erzeugen.

Der schöne Günther 29. Jan 2014 11:01

AW: Abstrakter Fehler bei leerer Prozedur
 
Da das standardmäßig eine Compiler-Warnung gibt (ich setze es immer auf FEHLER hoch) denke doch ich nicht, dass er das tut.

Codehunter 29. Jan 2014 12:16

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1245825)
Sind denn nach [Shift]+[F9] die blauen Haltepunkte noch da?

Dann mal zum Nachstellen: Wir reden über Delphi XE4 (Updates, Hotfixes?), kompiliert für Win32?

Blaue Pünktchen sind noch da nach Shift-F4 (beim begin und beim end der Proc1), XE4 Pro mit allen Updates und Hotfixes. Allerdings für Win64 kompiliert.
Zitat:

Zitat von Der schöne Günther (Beitrag 1245840)
Da das standardmäßig eine Compiler-Warnung gibt (ich setze es immer auf FEHLER hoch) denke doch ich nicht, dass er das tut.

Ich kenne das von D7 eigentlich noch so, dass sich der Compiler beschwert hat wenn man eine abstrakte Methode einer Basisklasse im Nachfahren nicht implementiert hat. Bei XE4 ist das nicht mehr so.
Zitat:

Zitat von Sir Rufo (Beitrag 1245828)
Zeig doch mal den ganzen Code und nicht nur das linke Ohr des Eisbären :)

Kann ich nicht, da spaltet mir mein Chef mit dem Wurfbeil den Schädel :roll: Wenn ich das auf das Wesentliche eindampfe bleibt eigentlich genau das übrig was DeddyH ganz oben auch schon gepostet hat:
Zitat:

Zitat von DeddyH (Beitrag 1245799)
Delphi-Quellcode:
type
  TClassA = class
  protected
    procedure Proc1; virtual; abstract;
  public
    procedure Proc2;
  end;

  TClassB = class(TClassA)
  protected
    procedure Proc1; override;
  end;

{ TClassA }

procedure TClassA.Proc2;
begin
  Proc1;
end;

{ TClassB }

procedure TClassB.Proc1;
begin
  inherited;

end;

procedure TFormTest.Button1Click(Sender: TObject);
var
  ClassB: TClassB;
begin
  ClassB := TClassB.Create;
  try
    ClassB.Proc2;
  finally
    ClassB.Free;
  end;
end;

Außer dass in procedure TClassB.Proc1; bei mir kein inherited drin stand, wobei das mit und ohne den selben Fehler produziert hat.

Sir Rufo 29. Jan 2014 12:29

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von Codehunter (Beitrag 1245847)
Zitat:

Zitat von Sir Rufo (Beitrag 1245828)
Zeig doch mal den ganzen Code und nicht nur das linke Ohr des Eisbären :)

Kann ich nicht, da spaltet mir mein Chef mit dem Wurfbeil den Schädel :roll: Wenn ich das auf das Wesentliche eindampfe bleibt eigentlich genau das übrig was DeddyH ganz oben auch schon gepostet hat:
Zitat:

Zitat von DeddyH (Beitrag 1245799)
Delphi-Quellcode:
type
  TClassA = class
  protected
    procedure Proc1; virtual; abstract;
  public
    procedure Proc2;
  end;

  TClassB = class(TClassA)
  protected
    procedure Proc1; override;
  end;

{ TClassA }

procedure TClassA.Proc2;
begin
  Proc1;
end;

{ TClassB }

procedure TClassB.Proc1;
begin
  inherited;

end;

procedure TFormTest.Button1Click(Sender: TObject);
var
  ClassB: TClassB;
begin
  ClassB := TClassB.Create;
  try
    ClassB.Proc2;
  finally
    ClassB.Free;
  end;
end;

Außer dass in procedure TClassB.Proc1; bei mir kein inherited drin stand, wobei das mit und ohne den selben Fehler produziert hat.

Funktioniert denn dieser Code bei dir?
Wenn ja, dann passe den weiter an die Original-Klassen an, bis dort der gleiche Fehler auftaucht.
Dieses Beispiel kannst du uns dann zeigen.

Das nennt sich SSCCE

Codehunter 29. Jan 2014 13:47

AW: Abstrakter Fehler bei leerer Prozedur
 
So das Problem hat sich auf mysteriöse Weise selbst erledigt. Nachdem ich alle DCUs (auch die von den Komponenten) gelöscht und alle Projekte neu erzeugt hatte, war der Fehler plötzlich verschwunden. Sowas hasse ich immer am meisten, wenn man nicht mal mehr nachvollziehen kann was schuld war.

Das genannte Beispiel von DeddyH war übrigens auch nicht lauffähig und produzierte ebenfalls abstrakte Fehler. Die sind nun ebenso verschwunden.

Schon seltsam.

guinnes 29. Jan 2014 14:56

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von Codehunter (Beitrag 1245855)
Das genannte Beispiel von DeddyH war übrigens auch nicht lauffähig und produzierte ebenfalls abstrakte Fehler.

Weil DeddyH in der überschriebenen Methode inherited aufruft. Damit wird natürlich der abstrakte Fehler ausgelöst

Stevie 29. Jan 2014 15:08

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von guinnes (Beitrag 1245865)
Zitat:

Zitat von Codehunter (Beitrag 1245855)
Das genannte Beispiel von DeddyH war übrigens auch nicht lauffähig und produzierte ebenfalls abstrakte Fehler.

Weil DeddyH in der überschriebenen Methode inherited aufruft. Damit wird natürlich der abstrakte Fehler ausgelöst

Ähm, nö? Ein inherited führt nicht zu einem abstract error, es sei denn, man benamt die aufzurufende Methode (hier nicht geschehen) explizit, wie Günther oben schon erwähnte.
Möglicherweise ist da irgendwas mit XE4 und Win64 im argen?

DeddyH 29. Jan 2014 15:15

AW: Abstrakter Fehler bei leerer Prozedur
 
Wie ich in #6 schon schrieb, löste Delphi 5 da noch einen abstrakten Fehler aus. Mindestens ab Delphi 7 (6 habe ich nicht) passiert das aber nicht mehr.

Codehunter 30. Jan 2014 09:02

AW: Abstrakter Fehler bei leerer Prozedur
 
Nachdem der Fehler dann gestern am späteren Abend wieder auftrat, habe ich das ganze Projekt mal probeweise auf Win32 umgestellt (eigentlich bauen wir hier ausschließlich x64) und tatsächlich tritt das dort nicht auf bzw. zumindest bis jetzt nicht reproduzierbar. Danach ist mir aufgefallen, dass der abstrakte Fehler nur dann auftritt, wenn ich für Debug kompiliere, nicht aber bei Release. Deshalb meldete ich gestern voreilig "Fehler beseitigt", da stand nach dem Komplett-Build das Projekt zufällig auf Release.

So bin ich auf die beiden DLLs FastMM_FullDebugMode.dll und FastMM_FullDebugMode64.dll gekommen. Nehme ich die FastMM_FullDebugMode64.dll aus dem Suchpfad, ist der Fehler auch im Debug-Build nicht mehr nachzuvollziehen. Dann funktionieren aber auch die Memdumps nicht mehr. So wie es aussieht ist da ein Bug im FastMM im 64-Bit-Modus.

jaenicke 30. Jan 2014 11:07

AW: Abstrakter Fehler bei leerer Prozedur
 
Die Ausgabepfade für Units enthalten aber korrekt $(Platform) und $(Config)?

Codehunter 30. Jan 2014 11:17

AW: Abstrakter Fehler bei leerer Prozedur
 
Zitat:

Zitat von jaenicke (Beitrag 1245955)
Die Ausgabepfade für Units enthalten aber korrekt $(Platform) und $(Config)?

Jepp :-) Über Mischmasch von Debug- und Release-DCUs bin ich früher schon bös auf die Nase gefallen.

Stevie 30. Jan 2014 13:12

AW: Abstrakter Fehler bei leerer Prozedur
 
Normalerweise verändert FastMM doch nicht den kompilierten Code, wie hier scheinbar geschehen (in inherited bei einer abstrakten Vorfahr Methode wird vom Compiler ignoriert, bzw sollte!).


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