Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Exception EAccessViolation bei inherited add() (https://www.delphipraxis.net/118574-exception-eaccessviolation-bei-inherited-add.html)

blackdrake 10. Aug 2008 23:38


Exception EAccessViolation bei inherited add()
 
Hallo.

Ich bin gerade dabei, eine VCL zu erweitern. Dabei erhalte ich nun eine EAccessViolation bei folgender Funktion:

Delphi-Quellcode:
function TSortListColumns.Add: TSortListColumn;
begin
  Result := TSortListColumn(inherited Add);
end;
Aufgedröselt kann ich erkennen, dass die Exception scheinbar durch inherited verursacht wird:

Delphi-Quellcode:
function TSortListColumns.Add: TSortListColumn;
var
  tmp: TListColumn;
  tmp2: TSortListColumn;
begin
  tmp := inherited Add; // <-- EXCEPTION (wieso da?)
  tmp2 := TSortListColumn(tmp);
  Result := tmp2;
end;
Der vereinfachte Code, der die zusammenhänge zeigt:

Delphi-Quellcode:
type
  TSortListColumns = class(TListColumns)
    {...}
  public
    function Add: TSortListColumn;
  end;

  TSortListView = class(TListView)
    {...}
  published
    property Columns: TSortListColumns read FSortListColumns write SetSortListColumns;
  end;
Die Exception wird ausgelöst bei dem Programmcode:

Delphi-Quellcode:
var tag_history: TSortListView;

tag_history := TSortListView.Create(TagForm);

{...}

with tag_history.Columns.Add do // <-- Exception
begin
  // ...
end;
Weiß jemand weiter? Ich kann mir absolut nicht vorstellen, was hier falsch sein soll, da ich Add() ja nur vererbe.

Ich kann ein kleines Testprogramm zur Verfügung stellen.

Gruß
blackdrake

mkinzler 11. Aug 2008 06:37

Re: Exception EAccessViolation bei inherited add()
 
Du musst Delphi auch sagen, das die Methode geerbt ist (overload)

marabu 11. Aug 2008 06:56

Re: Exception EAccessViolation bei inherited add()
 
Moin Daniel,

der Aufruf von inherited Add() schlägt wahrscheinlich fehl, weil du implizit im Konstruktor von TSortListView immer noch die Collection ListColumns mit der ItemClass TListColumn erzeugst.

Freundliche Grüße

DeddyH 11. Aug 2008 08:09

Re: Exception EAccessViolation bei inherited add()
 
Zitat:

Zitat von mkinzler
Du musst Delphi auch sagen, das die Methode geerbt ist (overload)

Statt overload override.

marabu 11. Aug 2008 08:16

Re: Exception EAccessViolation bei inherited add()
 
Hallo ihr beiden,

ich würde sagen "weder noch" - es geht hier um die statische Methode Add() der unterliegenden Collection.

Freundliche Grüße

DeddyH 11. Aug 2008 08:21

Re: Exception EAccessViolation bei inherited add()
 
Achso, Du meinst, dass weder die Item- noch die Listenklasse abgeleitet bzw. die Ableitungen im Konstruktor nicht benutzt wurden.

marabu 11. Aug 2008 08:43

Re: Exception EAccessViolation bei inherited add()
 
Moin Detlef,

die gewünschten Ableitungen (TListColumn, TListColumns, TSortListView) wurden ja hergestellt, aber im Konstruktor von TSortListView bleibt die Collection "Columns" die alte:

Delphi-Quellcode:
constructor TCustomListView.Create(AOwner: TComponent);
begin
  // ...
  FListColumns := TListColumns.Create(Self);
  // ...
end;
Leider kennt der Konstruktor der Collection nur seine eigene Item-Klasse:

Delphi-Quellcode:
constructor TListColumns.Create(AOwner: TCustomListView);
begin
  inherited Create(TListColumn);
  FOwner := AOwner;
end;
Es ist immer problematisch, wenn bei einer Ableitung auch noch eingebettete Klassen abgeleitet werden sollen und diese Vorgehensweise vom Designer der Klassenhierarchie nicht vorgesehen wurde. Daniel sollte vielleicht nochmal überlegen, ob sein Ansatz hier der richtige ist. Lässt TD nicht schon class decoration zu?

Freundliche Grüße

DeddyH 11. Aug 2008 08:47

Re: Exception EAccessViolation bei inherited add()
 
Moin Achim,

dann war mein weiterer persönlicher Gedankengang ja gar nicht so verkehrt. Ich hatte mich nämlich gefragt, wie zum Kuckuck man in einer Ableitung die "Originalliste" durch seine eigene ersetzen kann. Durch Vererbung ist diese ja bereits vorhanden, nur dann eben vom falschen Typ.

blackdrake 12. Aug 2008 13:25

Re: Exception EAccessViolation bei inherited add()
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.

Das mit overload funktioniert nicht, da die Originalmethode irgendwie virtuell ist.

Das mit dem Impliziten verstehe ich nicht ganz.

Wäre es möglich, dass ihr meinen Code einmal anschaut und mir Ratschläge gebt? Ich habe eine Beispielprojekt gepostet.

Das hier ist mein erster Versuch, irgendwas mit vererbten Klassen und VCLs zu tun. Ich habe daher in diesem Bereich das Wissen einer Tomate.

Ich habe ziemlich lange gebraucht, bis ich TColumn komplett zu TSortColumn erweitern konnte. Diese Column soll eine zusätzliche Eigenschaft "SortMode" haben (das heißt konvertierung von TColumn zu TSortColumn ist ohne Probleme möglich). Diese zusätzliche Eigenschaft beschreibt, mit welchen Sortieralgorithmus die Spalte beim Sortieren behandelt werden soll.

Es ist mir wichtig, dass ich beim Erweitern dieser VCL etwas lerne und mein Wissen über VCL, die properties und die Vererbungen erweitere.

PS: Ich würde außerdem gerne beim "alten" Delphi-Standard bleiben, sofern das in diesem Falle möglich ist. (Sprich: auf moderne Klassenerweiterungen / helper classes / decoration class / etc. verzichten)

Gruß
blackdrake

DeddyH 12. Aug 2008 13:54

Re: Exception EAccessViolation bei inherited add()
 
In der comctrls.pas von Delphi 5 steht Folgendes:
Zitat:

Delphi-Quellcode:
TCustomListView = class(TWinControl)
  private
    ...
    FListColumns: TListColumns;
    ...
    procedure SetListColumns(Value: TListColumns);
    ...
  protected
    ...
    property Columns: TListColumns read FListColumns write SetListColumns;
    ...
  end;

Da die Deklaration von FListColumns im private-Abschnitt steht, kommst Du da nicht ran, kannst also nicht ohne Weiteres auf Deinen Typ "umbiegen". Sofern Du über die VCL-Sourcen verfügst, bliebe Dir noch die Möglichkeit, die gesamte Kompo von Grund auf aufzubauen, den Originalsource könntest Du als Anhaltspunkt nehmen.

blackdrake 12. Aug 2008 14:01

Re: Exception EAccessViolation bei inherited add()
 
Hallo.

Man kann doch keine Grund-VCL verändern. Dann würde die VCL ja ohne diese Modifikation nicht laufen.

Ist es so abnormal, eine TColumn durch Ableiten erweitern zu wollen? Kann ich denn nicht einfach relevante Stellen überschreiben, die auf dieses private-Symbol zugreifen?

Ich verstehe außerdem das Problem nicht so ganz:

Wenn ich Funktionen wie z.B. Add() überschreibe, den Vorgänger mit inherited aufrufe und dann innerhalb meiner Funktion eine Konvertierung TColumn -> TSortColumn durchführe, müsste doch alles klaro sein, oder?

Wie sollte ich jetzt vorgehen? Bitte um Vorschläge.

Gruß
blackdrake

DeddyH 12. Aug 2008 14:02

Re: Exception EAccessViolation bei inherited add()
 
Wer hat denn gesagt, dass Du die VCL ändern sollst?

blackdrake 12. Aug 2008 14:05

Re: Exception EAccessViolation bei inherited add()
 
Entschuldige, ich habe da etwas falsch verstanden. Du meinst also, ich solle alle Stellen überschreiben, die mit TListColumns verbunden sind? Wäre dann die EAccessViolation weg, oder ist das eine Vermutung?

blackdrake 12. Aug 2008 14:09

Re: Exception EAccessViolation bei inherited add()
 
ADD:

Ich habe gerade bemerkt, dass ich diese Dinger bereits überschrieben habe:

Delphi-Quellcode:
  TSortListView = class(TListView)
  private
    FSortListColumns: TSortListColumns;
    procedure SetSortListColumns(Value: TSortListColumns);
    ...
  published
    property Columns: TSortListColumns read FSortListColumns write SetSortListColumns;
    ...
  end;

DeddyH 12. Aug 2008 14:44

Re: Exception EAccessViolation bei inherited add()
 
Was ich gemeint hatte war, den gesamten Source von TCustomListview zu kopieren, in dieser Kopie die relevanten Stellen zu ändern und die gewünschten Funktionalitäten zu ergänzen und das ganze dann als eigene Klasse zu speichern. Ist zwar viel Arbeit, aber eine saubere Lösung.

[edit] TCustomListview heißt das :oops: [/edit]

blackdrake 12. Aug 2008 14:54

Re: Exception EAccessViolation bei inherited add()
 
Hallo.

Reicht es denn nicht, die relevanten Stellen (die mit Column zu tun haben) in der Ableitung neu zu definieren? Ich habe ja wie bereits erwähnt die wichtigen Funktionen wie SetListColumns(), aber auch TLVColumnClickEvent ersetzt und neu definiert. Das ist doch der Sinn der Ableitung.

Ich wüsste jetzt nicht genau, was ich noch neu definieren sollte, da ich alle Column-Bezogenen Dinge bereits neu definiert / überschrieben habe (anders wäre der Code unkompilierbar gewesen).

Weißt du, wieso es zu der AccessViolation kommt? Für mich ist das immer noch ein Rätsel, da ich keinen Fehler und keine Ungereimtheit sehen kann.

Gruß
blackdrake

DeddyH 12. Aug 2008 14:58

Re: Exception EAccessViolation bei inherited add()
 
Schau Dir nochmal marabus Beitrag #7 an. Das kannst Du nicht ändern, da es als private deklariert ist.

blackdrake 12. Aug 2008 15:03

Re: Exception EAccessViolation bei inherited add()
 
Ist es denn nicht egal, wenn die untergeordnete Klasse ihr FListColumns vom Typ TListColumns hat?
Meine Klasse hat schließlich ihr eigenes FSortListColumns vom Typ TSortListColumns. Wenn meine Klasse diese Eigenschaft selbstständig handelt, dann ist es doch egal, wenn die untergeordneten Klassen mit dem nicht-erweiterten Typ TListColumns arbeiten, oder?

Verstehst du meinen Gedankengang? (Ist bestimmt absoluter Müll, was ich da denke)

Entschuldige bitte mein großes Unwissen. Wie ich bereits schrieb, habe ich sehr wenig Ahnung von Vererbung und VCL...

DeddyH 12. Aug 2008 15:06

Re: Exception EAccessViolation bei inherited add()
 
Ach du meinst, Du lässt die Originalliste einfach stehen und biegst die Property Items um? Das könnte evtl. sogar klappen :gruebel:
[edit] Columns, nicht Items (ich bin so verstreut heute :stupid:) [/edit]

blackdrake 12. Aug 2008 18:34

Re: Exception EAccessViolation bei inherited add()
 
Irgendwelche Ergebnisse erzielen können? Bei mir negativ. Ich habe lediglich noch herausgefunden, dass die EXE nach der EAccessViolation sich noch ausführen lässt. Aber den Grund habe ich immer noch nicht rausbekommen :(

DeddyH 12. Aug 2008 19:42

Re: Exception EAccessViolation bei inherited add()
 
Ich kämpfe im Moment "an allen Fronten", hab daher leider keine Luft, um mir das im Detail anzusehen. Evtl. morgen :|

blackdrake 18. Aug 2008 23:10

Re: Exception EAccessViolation bei inherited add()
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.

Ich habe bei meinem Demoprojekt die ganzen Schritte von OnCreate() in ein Button-Click-Ereignis geschoben (soll später in OnShow, mit Aufruf von Loaded). Bei OnCreate ist die ImageList ja noch gar nicht geladen, weswegen es das Loaded() Problem gab (das du für mich gefunden hast).

Ich erhalte bei folgender Stelle nun eine Meldung "Listenindex überschreitet Maximum 0":

Delphi-Quellcode:
with tag_history.Columns.Add do
begin
  Caption := '1'; // EXCEPTION
  Width := (tag_history.Width - 20) div 3 * 2;
end;
Das Seltsame:

Delphi-Quellcode:
function TSortListColumns.Add: TSortListColumn;
begin
  Result := TSortListColumn(inherited Add);
end;
Der Debugger sagt bei F7 nicht, dass es bei "inherited Add" weiter (in die "tiefe") geht!!

Normalerweise sollte er bei

Delphi-Quellcode:
{ ComCtrls }

function TListColumns.Add: TListColumn;
begin
  Result := TListColumn(inherited Add);
  UpdateCols;
end;
weitermachen! Hier wird der Haltepunkt aber niemals erreicht.

Auch die noch weiter oben liegende Weiterleitung

Delphi-Quellcode:
{ Classes }

function TCollection.Add: TCollectionItem;
begin
  Result := FItemClass.Create(Self);
  Added(Result);
end;
wird niemals erreicht...

Komisch. TSortListColumns ist das Kind von TListColumns, also müsste doch die inherited-Variante bei TListColumns.Add() anknüpfen, oder nicht???

Irgendeine Idee?

Gruß
Daniel Marschall
blackdrake

blackdrake 19. Aug 2008 21:32

Re: Exception EAccessViolation bei inherited add()
 
Kann mir denn niemand helfen? Wieso ruft inherited nicht die höhere Instanz auf? Ich habe sogar in die ComCtrls.pas eine showmessage() eingebaut, um ganz sicher zu gehen, dass sich der Debugger nicht geirrt hat. Der Punkt wird tatsächlich nicht erreicht.

Ich weiß nicht, ob das komplette Neuschreiben der Klasse überhaupt notwendig ist, da man es mit der Ableitung eigentlich prima hinbekommen könnte. (Schließlich macht es Borland meist genau so, z.B. mit den TCollectionItems, die einfach durch Ableiten erweitert werden)

blackdrake 21. Aug 2008 21:11

Re: Exception EAccessViolation bei inherited add()
 
Delphi-Quellcode:
function TSortListColumns.Add: TSortListColumn;
var
  x: TListColumn;
  y: TSortListColumn;
begin
  x := inherited Add;     // NACH DIESEM PUNKT IST MIT F7 DIE PROZEDUR ZUENDE!
                           // DER DEBUGGER GEHT NICHT IN DIE TIEFE
  y := TSortListColumn(x); // DIESER PUNKT WIRD NIEMALS ERREICHT
  Result := y;            // DIESER PUNKT WIRD NIEMALS ERREICHT

  //Result := TSortListColumn(inherited Add);
end;
Das kann doch nicht sein. Das Vererbungsmodell von Delphi funktioniert hier einfach nicht! Die Methode "Add" ist nicht als virtuell definiert, so dass man sie nicht mit override überschreiben kann.


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:02 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 by Thomas Breitkreuz