Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Aufruf abstrakter Methode führt zu Fehler (https://www.delphipraxis.net/158308-aufruf-abstrakter-methode-fuehrt-zu-fehler.html)

Jazzman_Marburg 12. Feb 2011 21:39

Aufruf abstrakter Methode führt zu Fehler
 
Hallo Gemeinde,
ich verstehe das Folgende nicht, und hoffe ihr habt eine Idee: Es kommt zum Fehler beim Aufruf einer abstrakten Methode.
Delphi-Quellcode:
  TFahrzeug = CLASS(TObject)

  ...
  PROCEDURE Verzoegern; VIRTUAL; ABSTRACT; // Fahrzeugabhängig, daher abstrakt.
  PROCEDURE Beschleunigen; VIRTUAL; ABSTRACT; // Fahrzeugabhängig, daher abstrakt.

  END;

  TPKW = CLASS(TFahrzeug)
  PRIVATE

  PROTECTED

  PUBLIC

    PROCEDURE Verzoegern; OVERRIDE;
    PROCEDURE Beschleunigen; OVERRIDE;
In meiner Oberklasse TFahrzeug habe ich zwei Methoden als Abstract deklariert, da sie erst im Nachfahren implementiert werden soll. Im Nachfahren habe ich diese Methoden mit OVERRIDE überschrieben und implementiert -- dennoch kracht es nun beim Aufruf einer dieser Methoden: 'Abstrakter Fehler'.
Ich sehe auch keine Warnung im Sinne von 'a verdeckt b'.

Jemand eine Idee, was ich da falsch mache?

Vielen Dank
Jazzman

Hansa 12. Feb 2011 21:49

AW: Aufruf abstrakter Methode führt zu Fehler
 
Welchen Vorteil erwartest Du denn von dem ABSTRACT ? Lasse das weg und mache leere Methode, die erst später konkret besetzt wird.

USchuster 12. Feb 2011 22:28

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von Jazzman_Marburg (Beitrag 1081310)
In meiner Oberklasse TFahrzeug habe ich zwei Methoden als Abstract deklariert, da sie erst im Nachfahren implementiert werden soll. Im Nachfahren habe ich diese Methoden mit OVERRIDE überschrieben und implementiert -- dennoch kracht es nun beim Aufruf einer dieser Methoden: 'Abstrakter Fehler'.
Ich sehe auch keine Warnung im Sinne von 'a verdeckt b'.

Jemand eine Idee, was ich da falsch mache?

Rufst Du zufällig
Delphi-Quellcode:
inherited Methodenname;
in den Implementierungen auf? (auch wenn das keinen Sinn macht)

Folgendes Beispiel funktioniert solange man nicht ABSTRACTERROR definiert.

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

{.$DEFINE ABSTRACTERROR}

uses
  SysUtils;

type
  TFahrzeug = class(TObject)
    procedure Verzoegern; virtual; abstract;
    procedure Beschleunigen; virtual; abstract;
  end;

  TPKW = class(TFahrzeug)
  public
    procedure Verzoegern; override;
    procedure Beschleunigen; override;
  end;

{ TPKW }

procedure TPKW.Beschleunigen;
begin
  inherited {$IFDEF ABSTRACTERROR}Beschleunigen{$ENDIF};
  asm
    nop
  end;
end;

procedure TPKW.Verzoegern;
begin
  inherited {$IFDEF ABSTRACTERROR}Verzoegern{$ENDIF};
  asm
    nop
  end;
end;

var
  Fahrzeug: TFahrzeug;
begin
  try
    Fahrzeug := TPKW.Create;
    try
      Fahrzeug.Beschleunigen;
      Fahrzeug.Verzoegern;
    finally
      Fahrzeug.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.

Jazzman_Marburg 12. Feb 2011 22:50

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von Hansa (Beitrag 1081312)
Welchen Vorteil erwartest Du denn von dem ABSTRACT ?

Hmmm... ich dachte 'man' macht es so -- es steht so in den Lehrbüchern... keine Ahnung!

Darüber muß ich nochmal nachdenken. :gruebel:

Jazzman

Jazzman_Marburg 12. Feb 2011 22:52

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von USchuster (Beitrag 1081319)
Rufst Du zufällig
Delphi-Quellcode:
inherited Methodenname;
in den Implementierungen auf?

Nein.

Den Rest (Beispiel) verstehe ich nicht. :pale:

Trotzdem Danke
Jazzman

BUG 12. Feb 2011 23:26

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von Jazzman_Marburg (Beitrag 1081326)
Hmmm... ich dachte 'man' macht es so -- es steht so in den Lehrbüchern... keine Ahnung!

Der Vorteil besteht darin, das man die Methoden implementieren muss.

Wenn man eine Klasse schreibt, deren Elternklasse TPerson die abstrakte Methode aufDenKopfStellen hat, sollte man diese Methode implementieren, denn irgendwo gibt es Code, der sich darauf verlässt, das sich das Objekt auf den Kopf stellt (egal wie es das anstellt!), wenn diese Methode aufgerufen wird. Wenn die Methode in der Elternklasse einfach leer gelassen würde, wäre das nicht ersichtlich.

So würde der Code, der dem TPerson-Objekt ein paar warme TSocken anziehen soll, diesem die eventuell über die Ohren ziehen, weil sich das Objekt nicht ordnungsgemäß mit den Füßen nach oben auf den Kopf gestellt hat :drunken:

Und das würdest du beim Kompilieren dann nicht merken.

r2c2 13. Feb 2011 08:39

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zeig mal den Methodenaufruf. Bist du dir sicher, dass du das richtige Objekt instanziiert hast und die richtige Methode aufrufst?

mfg

Christian

Hansa 13. Feb 2011 10:36

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von BUG (Beitrag 1081333)
Der Vorteil besteht darin, das man die Methoden implementieren muss.

@BUG : das ist kapitaler Denk-Bug. :mrgreen: "implementieren" würde ich an dieser Stelle auf deutsch als "umsetzen" bezeichnen. Oder "mit Leben erfüllen". Abstrakte Methoden zeichnen sich aber genau dadurch aus, dass sie nicht konkret vorhanden sind. Sie sind lediglich deklariert. Was wiederum heisst : es wurde ein Name vergeben für etwas, das nicht vorhanden, besser gesagt noch nicht umgesetzt ist. Denkt man jetzt, die Methode wäre bereits "implementiert", die ist es aber nicht, dann kommt "abstrakter Fehler", sofern man die benutzen will.

Deshalb mein Vorschlag, die Methode als leeren Rumpf zur Verfügung zu stellen und nicht nur zu deklarieren. Unterschied ist :
Delphi-Quellcode:
virtual; abstract
und
Delphi-Quellcode:
virtual;
machen beide nichts, was nicht implementiert ist. Kommt "abstract" zusätzlich ins Spiel, dann wird wie gesagt, nichts gemacht, ausser zusätzlich eine Fehlermeldung zu produzieren.

BUG 13. Feb 2011 10:46

AW: Aufruf abstrakter Methode führt zu Fehler
 
Ich glaube, ich habe mich etwas schwammig ausgedrückt.
Zitat:

Zitat von Hansa (Beitrag 1081370)
Denkt man jetzt, die Methode wäre bereits "implementiert", die ist es aber nicht, dann kommt "abstrakter Fehler", sofern man die benutzen will.

Das sehe ich als Vorteil. Leere Methoden sind nicht in allen Fällen korrekte Implementierungen für bestimmte Methoden.

Wenn ich einen abstrakten Fehler bekomme, habe ich dann die Wahl:
  1. die Methode "richtig" zu implementieren
  2. eine leere Methode zu erstellen und zu wissen, das irgendwas schief gehen kann
In beiden Fällen habe ich darüber nachgedacht, was ich tue.
Ohne abstract hätte ich nicht mitgekriegt, das überhaupt etwas schief laufen könnte.

Sir Rufo 13. Feb 2011 10:51

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von BUG (Beitrag 1081374)
Ich glaube, ich habe mich etwas schwammig ausgedrückt.
Zitat:

Zitat von Hansa (Beitrag 1081370)
Denkt man jetzt, die Methode wäre bereits "implementiert", die ist es aber nicht, dann kommt "abstrakter Fehler", sofern man die benutzen will.

Das sehe ich als Vorteil. Leere Methoden sind nicht in allen Fällen korrekte Implementierungen für bestimmte Methoden.

Wenn ich einen abstrakten Fehler bekomme, habe ich dann die Wahl:
  1. die Methode "richtig" zu implementieren
  2. eine leere Methode zu erstellen und zu wissen, das irgendwas schief gehen kann
In beiden Fällen habe ich darüber nachgedacht, was ich tue.
Ohne abstract hätte ich nicht mitgekriegt, das überhaupt etwas schief laufen könnte.

Genau so ist das :thumb:
Eine Art Documentation by Design

Bummi 13. Feb 2011 10:58

AW: Aufruf abstrakter Methode führt zu Fehler
 
:thumb:

r2c2 13. Feb 2011 10:59

AW: Aufruf abstrakter Methode führt zu Fehler
 
Und noch mehr: Man erhält i.d.R. eine Warnung zur Compiletime (in anderen Sprachen sogar einen Fehler). Das hilft Bugs gar nicht erst entstehen zu lassen.

Das mit den leeren Methoden kann auch seinen Sinn haben. Wenn diese von anderen (nicht abstrakten) Methoden aufgerufen werden, wären das dann so genannte HookMethods. Also quasi Stellen, in die ich Code einfügen kann, aber nicht muss. Abstrakte Methoden sind hingegen eher TemplateMethods. Hier *muss* ich etwas implementieren. Beides braucht man oft, wenn man n Framework schreibt.

Abstrakte Methoden, die nicht unbedingt intern aufgerufen werden, gibt es auch sehr oft in Klassen, die die Anwendungsdomäne modellieren.

In leeren Methoden, die keine HookMethoden sind, sehe ich momentan keinen sonderlichen Sinn. Fällt euch einer ein?

Fakt ist, dass die Exception "Abstrakter Fehler" auf einen Bug hindeutet. Man könnte die Exception unterdrücken, wenn man ne leere Methode dafür einsetzt. Der eigentliche Bug wird dadurch aber nicht behoben...

mfg

Christian

Sir Rufo 13. Feb 2011 11:20

AW: Aufruf abstrakter Methode führt zu Fehler
 
Eine relativ simple Klasse die man sich als Beispiel dazu anschauen kann ist Delphi-Referenz durchsuchenTStrings und als Ableitung davon Delphi-Referenz durchsuchenTStringList

Hansa 13. Feb 2011 12:21

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von BUG (Beitrag 1081374)
Ohne abstract hätte ich nicht mitgekriegt, das überhaupt etwas schief laufen könnte.

Du kriegst es aber erst mit, wenn es zu spät ist. Weil das hier :

Zitat:

Zitat von Sir Rufo (Beitrag 1081378)
Eine Art Documentation by Design

so nicht stimmt. Man könnte allenfalls sagen : "Dokumentation durch Laufzeitfehler". :shock: Ich sehe das allerdings wohl zu sehr aus Sicht des Endbenutzers. Leere Methode einbauen oder lediglich sowas :
Delphi-Quellcode:
showmessage ('Funktion kommt mit nächster Version');
Alternative : nur "abstract" deklarieren und es kommt das:

Zitat:

---------------------------
Testpro
---------------------------
Zugriffsverletzung bei Adresse 004DD37D in Modul 'TestPro.exe'. Lesen von Adresse 00000000.
---------------------------
OK
---------------------------
Ungeduldiger Enduser würde wohl folgendes sagen : Fall 1 : "wann geht denn das endlich ?" Fall 2 : "ihr Scheissprogramm geht ja immer noch nicht ! Kommen morgen immer noch Fehlermeldungen, dann wollen wir unser Geld zurück !" Die Theoretiker können ja dann mit ABSTRACT ankommen, dass das eben so ist. :mrgreen: Ähnlich sieht es auch mit der Frage aus, um die es hier geht. Ohne ABSTRACT bräuchte man hier gar nicht zu diskutieren. 8-)

Sir Rufo 13. Feb 2011 12:26

AW: Aufruf abstrakter Methode führt zu Fehler
 
@Hansa ich weiß nicht wo du bist, wir sprechen hier über virtal abstract und da gibt es einen Compiler-Fehler wenn nicht deklariert wurde.

Vielleicht hast du dich ja im Thread geirrt

Ach, das mit der Dokumentation meine ich nicht als Doku für den Enduser sondern für den Entwikler der eine Basisklasse erweitern möchte/soll/muss.

Hansa 13. Feb 2011 12:56

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von Sir Rufo (Beitrag 1081402)
... wir sprechen hier über virtal abstract...

Du meinst wohl "virtual". Ich rede jedenfalls über so etwas :

Delphi-Quellcode:
type
  TKlasse1 = class
     procedure test; virtual; abstract;
  end;

  TKlasse2 = class (TKlasse1)
     procedure test;
  end;

var
  Klasse1 : TKlasse1;
  Klasse2 : TKlasse2;
ABSTRACT alleine geht überhaupt nicht !


Zitat:

..und da gibt es einen Compiler-Fehler wenn nicht deklariert wurde
Nein, aber wenn es fehlerhaft implementiert ist, also :

Delphi-Quellcode:
type
  TKlasse1 = class
     procedure test; virtual; abstract;
  end;

var
  Klasse1 : TKlasse1;

procedure TKlasse1.UndeklarierteImplementierung;
begin
end;
aber nicht deklariert ist (in der Klassen-Definition), dann ist die Prozedur erstens "unknown identifier" und zusätzlich kommt noch "Ungenügende Forward- oder External-Deklaration". Ist die Prozedur deklariert mit ABSTRACT, dann reicht das. Mehr geht nicht mal (insbesondere keine konkrete Implementierung). Dann kommt nämlich hier :

Delphi-Quellcode:
procedure TKlasse1.test;
begin
  ShowMessage('');
end;
dieser Compilerfehler :
Zitat:

[Fehler] TestUnit.pas(45): Definition für abstrakte Methode 'test' nicht erlaubt
In obigem Fall muss/darf die
Delphi-Quellcode:
procedure TKlasse1.Test;
nicht implementiert werden, man kann im Programm trotzdem auf diese Prozedur zugreifen und produziert damit erst zur Laufzeit einen Fehler. Trotz des Fehlers lässt sich eine EXE erstellen, die lauffähig ist und eben Fehlermeldungen produziert. So richtig nach dem Motto : "es compiliert, wir können ausliefern". :mrgreen:

Hawkeye219 13. Feb 2011 13:55

AW: Aufruf abstrakter Methode führt zu Fehler
 
Hallo,

bei neueren Delphi-IDEs kann man Warnungen des Compilers über die Projektoptionen in Fehlermeldungen umwandeln (Delphi-Compiler -> Hinweise und Warnungen: "Ausgabewarnungen"). Für ältere IDEs stellen die DDevExtensions eine entsprechende Funktionalität bereit.

Gruß Hawkeye

alzaimar 13. Feb 2011 15:37

AW: Aufruf abstrakter Methode führt zu Fehler
 
Hansa's Ansatz bedeutet einfach: "Die Methode kannst Du überschreiben, musst Du aber nicht". Der 'abstract' Ansatz bedeutet einfach: "Du musst die Methode noch überschreiben".

Schön wäre es, wenn der Compiler beim abstract-Ansatz wirklich einen Fehler moniert. Leider macht er das wohl nicht, aber man kann sich auch so herausreden, das ein guter Entwickler sowieso eine umfangreiche Test-Unit mit seiner Klasse ausliefert, die dann auf nicht implementierten Methoden prüft.

Ansonsten rennt ihr euch hier in Klugscheißerei fest, wenn ihr so weiter macht. Bisher ist davon natürlich weit und breit nichts zu sehen.:mrgreen:

Hansa 13. Feb 2011 16:18

AW: Aufruf abstrakter Methode führt zu Fehler
 
Zitat:

Zitat von alzaimar (Beitrag 1081431)
..Schön wäre es, wenn der Compiler beim abstract-Ansatz wirklich einen Fehler moniert. Leider macht er das wohl nicht...

Der Compiler wird das nie machen KÖNNEN ! Wie denn ? Der hat ja nur einen Namen und das wars. Und er muss das abstrakte ja compilieren. Sonst ist bei
Delphi-Quellcode:
virtual; abstract;
ja nichts da. Beim Debugger gehts dann weiter. Wo soll denn der anhalten ?

Mir wirds aber auch zu blöd. Wer unbedingt unnötige Fehlermeldungen im eigenen Programm haben will, der soll die Implementierung (auch wenn sie leer sein sollte) eben einfach weglassen.

FaTaLGuiLLoTiNe 13. Feb 2011 17:24

AW: Aufruf abstrakter Methode führt zu Fehler
 
Eine Klasse ist abstrakt, wenn sie entweder selber abstrakte Methoden deklariert oder solche von einer Elternklasse erbt, aber nicht selbst implementiert (überschreibt).

Da das Deklarieren einer abstrakten Klasse an sich nichts Verwerfliches ist, gibt der Compiler natürlich keine Warnung aus, wenn er eine solche findet. Die Warnung kommt erst dann, wenn man versucht, eine abstrakte Klasse zu instanziieren.

Delphi-Quellcode:
program AbstraktTest;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TAbstraktBasis = class(TObject)               // Abstrakte Klasse, da abstrakte Methode deklariert
  public
    procedure Methode; virtual; abstract;
  end;

  TAbstraktAbgeleitet = class(TAbstraktBasis);  // Abstrakte Klasse, da abstrakte Methode geerbt

  TKonkretAbgeleitet = class(TAbstraktBasis)   // Keine abstrakte Klasse, da Methode implementiert
  public
    procedure Methode; override;
  end;

{ TKonkretAbgeleitet }

procedure TKonkretAbgeleitet.Methode;
begin
 WriteLn('Methode wurde implementiert');
end;

{ Programmcode }

var AbstraktBasis: TAbstraktBasis;
    AbstraktAbgeleitet: TAbstraktBasis;
    KonkretAbgeleitet: TKonkretAbgeleitet;

begin
 // Versuche, abstrakte Basisklasse zu instanziieren:
 AbstraktBasis := TAbstraktBasis.Create;

 // Versuche, abstrakte abgeleitete Klasse zu instanziieren:
 AbstraktAbgeleitet := TAbstraktAbgeleitet.Create;

 // Versuche, konkrete abgeleitete Klasse zu instanziieren:
 KonkretAbgeleitet := TKonkretAbgeleitet.Create;
end.
Zitat:

Zitat von Delphi 7 - Compiler
[Warnung] AbstraktTest.dpr(36): Instanz von 'TAbstraktBasis' mit der abstrakten Methode 'TAbstraktBasis.Methode' wird angelegt
[Warnung] AbstraktTest.dpr(39): Instanz von 'TAbstraktAbgeleitet' mit der abstrakten Methode 'TAbstraktBasis.Methode' wird angelegt

Also ist die Aussage, der Compiler würde 'beim abstract-Ansatz keinen Fehler monieren', schlichtweg falsch. Oder habe ich jetzt das Thema verfehlt?

Blup 16. Feb 2011 11:54

AW: Aufruf abstrakter Methode führt zu Fehler
 
Die einzige Schwachstelle des Compilers ist, das er an dieser Stelle nicht warnt:
Delphi-Quellcode:
procedure TKonkretAbgeleitet.Methode;
begin
 inherited Methode; // <- keine Warnung
 WriteLn('Methode wurde implementiert');
end;
Und dieser Programmierfehler wird auch hier die Ursache des Problems sein.

FaTaLGuiLLoTiNe 16. Feb 2011 12:08

AW: Aufruf abstrakter Methode führt zu Fehler
 
Hmmm... Tatsache. Das ist wirklich suboptimal.

DeddyH 16. Feb 2011 12:25

AW: Aufruf abstrakter Methode führt zu Fehler
 
Das finde ich nicht. Ansonsten müsste ich ja erst nachschauen, ob die Methode in der Elternklasse implementiert wurde. So juckt mich das nicht, mit dem inherited-Aufruf bin ich auf der sicheren Seite.

SirThornberry 16. Feb 2011 12:27

AW: Aufruf abstrakter Methode führt zu Fehler
 
Könntet ihr bitte zurück zum Thema kommen anstelle eine Grundsatzdiskussion zu führen?

Zitat:

So juckt mich das nicht, mit dem inherited-Aufruf bin ich auf der sicheren Seite.
Nur wenn du es nicht wie in obigem Beispiel geschrieben hast.

folgendes kann wirklich der Fehler sein:
Delphi-Quellcode:
procedure TKonkretAbgeleitet.Methode;
begin
 inherited Methode; // <- Fehlermeldung weil explizit eine abstrakte Methode aufgerufen wird
 WriteLn('Methode wurde implementiert');
end;
aber sowas kann man umgehen indem man schreibt:
Delphi-Quellcode:
procedure TKonkretAbgeleitet.Methode;
begin
 inherited;
 WriteLn('Methode wurde implementiert');
end;
Am besten wäre Quelltext von der Stelle an der, der Fehler auftritt.


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