myeunit.pas(210,17) Error: There is no method in an ancestor

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
thosch
Beiträge: 324
Registriert: Mo 10. Jul 2017, 20:32

myeunit.pas(210,17) Error: There is no method in an ancestor

Beitrag von thosch »

Hallo,

ich erhalte in einer Programmbibiliothek für mehrere Methoden, die in der Basisklasse definitiv vorhanden sind, die im Threadtitel genannte Fehlermeldung. In der Basisklasse sind die fraglichen Methoden als virtual; abstract; mit derelben Parameterliste definiert, wie in der abgeleiteten Klasse, wo sie überschrieben werden sollen, um definiert zu werden. In abgeleiteter, wie in der Basisklasse auch sind die fraglichen Methoden in derselben Sichtbarkeitsstufe.

Warum erhalte ich da die besagte Fehlermeldung?

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1430
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: myeunit.pas(210,17) Error: There is no method in an ance

Beitrag von fliegermichl »

Definitiv nicht. Poste doch mal ein nachvollziehbares Beispiel.

thosch
Beiträge: 324
Registriert: Mo 10. Jul 2017, 20:32

Re: myeunit.pas(210,17) Error: There is no method in an ance

Beitrag von thosch »

.
Ok, hier das Beispiel. Dieses hier funktioniert. Was also kann da schief laufen? Wo muss ich in meiner komplexeren Klassenbibliothek genauer hinschauen. Denn auch in dieser gibt es die betroffenen Methoden mit exakt gleicher Parameterliste und exakt gleichen Namen wie auch exakt als Function bzw Procedure sowohl als virtual; abstract; als auch als override;

Code: Alles auswählen

 
type
  TMyBaseClass = class(TObject)
  private
    FAnyField: Integer;
  protected
    function GetTheFildValue: Integer; virtual; abstract;
  public
    procedure SetTheFieldValue(Value: Integer); virtual; abstract;
  end;
 
  TMyClass = class(TMyBaseClass)
  protected
    function GetTheFildValue: Integer; override;
  public
    procedure SetTheFieldValue(Value: Integer); override;
  end;
 
{ TMyClass }
 
function TMyClass.GetTheFildValue: Integer;
begin
 
end;
 
procedure TMyClass.SetTheFieldValue(Value: Integer);
begin
 
end;
 


In diesem Beispiel funktioniert es.

In meiner realen Klassenbibliothek sagt mir der Compiler nun aber, dass es keine Methoden zum Überschreiben gäbe.

Warum funktioniert das hier, aber nicht in meiner komplexeren Klassenbibliothek. Ich habe dort nur einige vorausgesetzte Units verändert, die jedoch keinerlei andere Klassendefinitionen enthalten. Was also kann da noch schief laufen. Ich hatte diesen Fehler schon mal vor längerer Zeit bei einer anderen Klassenbibliothek.

In der besagten komplexeren Klassenbibliothek befinden sich Basisklasse und abgeleitete Klasse in zwei verschiedenen Units.

.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: myeunit.pas(210,17) Error: There is no method in an ance

Beitrag von Warf »

thosch hat geschrieben:In diesem Beispiel funktioniert es.

In meiner realen Klassenbibliothek sagt mir der Compiler nun aber, dass es keine Methoden zum Überschreiben gäbe.
[...]
In der besagten komplexeren Klassenbibliothek befinden sich Basisklasse und abgeleitete Klasse in zwei verschiedenen Units.


Ein funktionierendes beispiel bringt ja herzlich wenig. Nimm doch einfach mal deine komplexe klassenbibliothek und reduzier sie, statt ein neues funktionierendes beispiel zu schreiben.
Begin erst mal damit das du die gesammte implementation rauswirfst, die hat mit dem problem nix zu tun. Dann wirfst du alle klassen raus die nicht mit dieser klasse zusammenhängen.
Jetzt sollte der Fehler ja immernoch auftreten, nur du hast schonmal den großteil deiner bibliothek eliminiert.
Dann wirf immer mehr raus. Sei dabei nicht kleinschrittig, sondern geh einfach in die datei und werf einfach mal die hälfte der zeilen raus. Wenn dardurch neue fehler reinkommen (z.B. bezeichner die gebraucht werden hast du rausgeworfen) ersetz die bezeichner durch andere, Z.B. kannst du klassennamen durch TObject ersetzen.
Wenn beim rauswerfen der fehler nicht mehr auftaucht, weist du das er in dem Teil vom code war, ansonsten nimm dir wieder ne hälfte an zeilen code und wirf die raus. Am ende sollte aus deiner komplizierten Klassenbibliothek nur noch ein paar klassen rauskommen.

Sachen die du rauswerfen kannst:
1. Andere klassen, die vorkomnisse dieser klassen einfach durch TObject ersetzen (da die implementation rausgeflogen ist, macht das ja eh nix aus)
2. Stufen in Klassenhierachien. Sagen wir du hast klasse A, B, C A erbt von B erbt von C, und der fehler ist in A und C (also A implementiert ne abstrakte methode von C) dann kannst du B einfach rausschmeißen und A direkt von C erben lassen. Wenn A aus B implementiert kannst du C einfach rausschmeißen, und wenn B von C, kannst du A rausschmeißen
3. Felder und andere funktionen. Ohne implementierung brauchst du keine daten, also kannst du alle variablen/Felder deiner Klassen schonmal von anfang an rausschmeißen. Da das ein vererbungs problem ist auch alle funktionen die nicht virtual oder override sind.

Selbst wenn du ne 10,000 zeilen Klassenbibliothek hast, solltest du (wenn du immer genau die hälfte an zeilen rausschmeißt) nach maximal 15 rausschmeißoperationen deinen fehler gefunden haben. (Für C gibt es sogar programme die das voll automatisch machen, für pascal leider meines wissens nach nicht). Du musst halt in jedem schritt schauen ob der fehler noch auftritt, wenn nicht hast du was gelöscht was dafür gesorgt hat das der fehler auftritt. Wenns z.B. ein FPC bug wäre, kann es sein das ganz andere klassen den hervorrufen. Also immer hälfte löschen, kompilieren->Fehler noch da?: Nächste hälfte löschen, fehler nicht mehr da? dann weist du der fehler, oder ein teil des fehler ist in dieser hälfte, fängst also an diese hälfte zu reduzieren. Egal welcher der beiden fälle eintritt, in jedem schritt musst du nur noch die hälfte des codes betrachten

Der fehler den du hast, entsteht vor allem im klassen parsen, wird also bereits vor dem Forward definiton nicht gefunden fehler geworfen, was bedeutet das du sogar wirklich alles unterhalb von implementation rauswerfen kannst, da das diesen fehler nicht beeinflussen kann (und der compiler wird deinen fehler finden bevor er meckert das es keine implementation gibt).

Und wenn du ein reduziertes beispiel hast, und den fehler dann nicht schon selbst gefunden hast (meist lacht der einen ins gesicht wenn man erst mal alles reduziert hat), kannst du dann doch das hier posten.

thosch
Beiträge: 324
Registriert: Mo 10. Jul 2017, 20:32

Re: myeunit.pas(210,17) Error: There is no method in an ance

Beitrag von thosch »

Danke erst mal so weit, da weiß ich wenigstens erst mal, wo ich mit der Fehlersuche ansetzen muss bzw. wie ich da vorgehen muss :)

Mach ich morgen. Wenn Fehler gefunden, poste ich das mit Fehlerursache gerne hierher.

thosch
Beiträge: 324
Registriert: Mo 10. Jul 2017, 20:32

Re: myeunit.pas(210,17) Error: There is no method in an ance

Beitrag von thosch »

Hallo,

ich wollte doch noch mal eine Rückmeldung geben, wenn ich die Fehlerursache gefunden habe.

In meiner Klassenbibliothek hatte ich in einer der Units vorausgesetzte Units ausgetauscht. In einer der neu vorausgesetzten Units wurde ein Datentyp neu definiert. Nun war aber die Basisklasse in einer weiteren Unit definiert, die auch weiterhin vorausgesetzt wird und auch in der Uses Klausel enthalten ist. Aber in der Basisklasse wurde noch der vorherige gleichnamige Datentyp verwendet.

So hier:

In Basisklasse (In separater Unit):

Code: Alles auswählen

 
unit meineBasisklasse;
 
Interface
 
Uses ...
 
type
  TData = Integer;
  TMyBaseClass = class
  ...
    procedure DoSomething(withThis: TData); virtual; abstract;
  ...
  end;
 
implementaion
 
  ....
 
end.
 


Und nun die Unit, welche die Basisklasse ableitet:

Code: Alles auswählen

 
unit myAncestrorClass;
 
uses
  UAusgetauschteUnit;
 
type
  TData = TMyRedefinedData;
  TMyAncestorClass = class(TMyBaseClass)
     ...
    procedure DoSomething(withThis: TData); override;
    ...
  end;
 
implementation
  ....
end.
 
unit UAusgetauschteUnit;
 
interface
 
type
  TMyRedefinedData = record
       Data: String;
       ID: Integer;
  end;
 
implementation
 
end.
 


Und weil nun zwar der Name des Datantyps in Basisklasse und abgeleiteter Klasse zwar gleich war, aber unterschiedlich definiert, hatte ich den Fehler.

.

Antworten