![]() |
Delphi-Version: XE
Generics und Vererbung
Ich arbeite derzeit daran, meine Graphenbibliothek in gerichtete und ungerichtete Graphen aufzuteilen. Dabei ist viel Code redundant, so dass ich mir einen TBasicGraph als Elternklasse konstruiert habe. Jetzt habe ich aber ein Proble mit der Verwaltung der Kanten.
TDirectedGraph verwaltet Kanten vom Typ TDirectedEdge TUndirectedGraph verwaltet Kanten vom Typ TEdge Die Elternklasse TBasicGraph soll eine gemeinsame Elternklasse aller Kanten nutzen, nämlich TBasicEdge. Das klappt soweit ganz gut. Aber ich muss alle Kanten in einer Liste verwalten. Das ganze sah bisher so aus:
Delphi-Quellcode:
Durch diese "doppelte" Verschachtelung bin ich jetzt überfragt, wie ich eine TBasicEdgeList konstruieren kann, von denen die beiden anderen Klassen abgeleitet sind.
TDirectedEdgeList<T, V> = class(TList < TDirectedEdge < T, V >> );
TEdgeList<T, V> = class(TList < TEdge < T, V >> ); Edit: Eine Idee wäre den konkreten Datentyp als dritten generischen Parameter mitzugeben und über Constraints entsprechend einzuschränken.
Delphi-Quellcode:
Das scheitert aber schon an der ersten Deklaration: "Undeklarierter Bezeichner: 'ET<,>' "
TBasicEdgeList<T, V, ET: TBasicEdge<T, V>, constructor> = class(TList < ET < T, V >> );
TDirectedEdgeList<T,V> = class(TBasicEdgeList<T,V,TDirectedEdge<T,V>>); |
AW: Generics und Vererbung
Delphi-Quellcode:
geht halt nicht. Man kann nur sowas sagen, wie record oder class.
<ET: TBasicEdge>
Auf eine bestimmte Klasse kann man (bescheuerter Weise) keinen Typen einschränken. Du müßtest TBasicEdge<T, V> also erst bei der Implementation deines neuen Typs angeben. evtl so?
Delphi-Quellcode:
TBasicEdgeList<T, V, ET: class> = class(TList<ET>);
TEdge = TBasicEdge<T, V, TBasicEdge<T, V>> |
AW: Generics und Vererbung
Ganz so klappt es nicht, aber du hast mich auf die richtige Idee gebracht.
Delphi-Quellcode:
muss weg, weil sonst meckert der Compiler in der vererbten Klasse, es wäre kein Klassentyp :roll:. Die direkte Zuweisung über das Gleichheitszeichen mag er auch nicht. Mit ein bißchen basteln, kommt man dann aber auf eine funktionierende Lösung:
class
Delphi-Quellcode:
Sieht zwar aus wie ein Klammerirrgarten, aber scheint genau das zu tun, was es soll.
TBasicEdgeList<T, V, ET> = class(TList<ET>);
TDirectedEdgeList<T, V> = class(TBasicEdgeList < T, V, TDirectedEdge < T, V >> ); TEdgeList<T, V> = class(TBasicEdgeList < T, V, TEdge < T, V >> ); Edit: Kommando zurück. Mit dem dritten Parameter handele ich mir aber Ärger in der Graphenklasse ein. Ich muss das Attribut ja irgendwie deklarieren und da muss ich den dritten Parameter ja schon wieder mitgeben.
Delphi-Quellcode:
TBasicGraph<E, V> = class
private FEdges: TBasicEdgeList<E, V>; // <-- hier knallt es weil der Parameter fehlt, den ich aber in der Basisklasse zu diesem Zeitpunkt nicht kenne |
AW: Generics und Vererbung
Zitat:
Delphi-Quellcode:
Wenn du diesen Typen nicht schon
TBasicGraph<E, V> = class
private FEdges: TBasicEdgeList<E, V, TBasicEdge<E, V>>;
Delphi-Quellcode:
benötigen würdest, dann wäre ein Subtype möglich gewesen.
type TBasicEdgeList<...> = class( {hier} );
Delphi-Quellcode:
TBasicGraph<E, V> = class
private type TMyBasicEdge = TBasicEdge<E, V>; ... end; |
AW: Generics und Vererbung
Zitat:
"[DCC Fehler] GenericGraph.BasicGraph.pas(92): E2010 Inkompatible Typen: 'GenericGraph.Global.TBasicEdgeList<GenericGraph.B asicGraph.TBasicGraph<E,V>.E,GenericGraph.BasicGra ph.TBasicGraph<E,V>.V,GenericGraph.Global.TBasicEd ge<GenericGraph.BasicGraph.TBasicGraph<E,V>.E,Gene ricGraph.BasicGraph.TBasicGraph<E,V>.V>>' und 'GenericGraph.Global.TDirectedEdgeList<GenericGrap h.BasicGraph.TBasicGraph<E,V>.E,GenericGraph.Basic Graph.TBasicGraph<E,V>.V>'" Ich versuche nochmal den Quelltext etwas strukturierter zusammenzuschreiben:
Delphi-Quellcode:
Für die jeweiligen Graphenklassen
{ Elternklasse für alle Kanten }
TBasicEdge<T, V> = class {...} end; { Kanten für gerichtete Graphen} TDirectedEdge<T, V> = class(TBasicEdge<T, V>) {...} end; { Kanten für ungerichtete Graphen } TEdge<T, V> = class(TBasicEdge<T, V>) {...} end;
Delphi-Quellcode:
und
TDirectedGraph<E, V>
Delphi-Quellcode:
wollte ich eine gemeinsame Oberklasse
TUndirectedGraph<E, V>
Delphi-Quellcode:
einführen, weil die ja ziemlich viel gemeinsam haben. Diese sollte
TBasicGraph<E, V>
Delphi-Quellcode:
heißen. Die Kanten selbst werden in einer einfachen Liste verwaltet. Das waren bisher die Typen
TBasicGraph<E, V>
Delphi-Quellcode:
und
TDirectedEdgeList<T,V>
Delphi-Quellcode:
. In der Elternklasse
TEdgeList<,V>
Delphi-Quellcode:
muss ich diese Liste jetzt irgendwo als privates Attribut anlegen, erstellen, usw.
TBasicGraph<E, V>
Das sieht im Moment so aus:
Delphi-Quellcode:
Wenn ich jetzt versuche, FEdges mit einem konkreten Typen zu erstellen
TBasicGraph<E, V> = class
private FEdges: TBasicEdgeList<E, V, TBasicEdge<E, V>>; {...}
Delphi-Quellcode:
bekomme ich diese nette und übersichtliche Fehlermeldung von oben.
FEdges := TDirectedEdgeList<E, V>.Create()
|
AW: Generics und Vererbung
Zitat:
Delphi-Quellcode:
program Project110;
{$APPTYPE CONSOLE} type TFoo = class(TObject); TBar<T: TFoo> = class(TObject) end; var B: TBar<TFoo>; B2: TBar<TObject>;//[DCC Error] Project110.dpr(13): E2515 Type parameter 'T' is not compatible with type 'TFoo' begin end. |
AW: Generics und Vererbung
Zitat:
|
AW: Generics und Vererbung
Haben die das in XE nun eingebaut?
Kann aber auch sein, daß ich in einen anderen Genericfehler reinlief, denn als ich sowas mal versuchte, ging es nicht. |
AW: Generics und Vererbung
Wenn ich das richtig sehe, ist dein Problem, dass TBasicEdgeList<E, V, TDirectedEdge<E, V>> nicht von TBasicEdgeList<E, V, TBasicEdge<E, V>> abgeleitet ist, was in einer Sprache ohne Kovarianz wie Delphi auch vollkommen korrekt ist. Mit diesem Ansatz wirst du also an der Stelle ein wenig Typsicherheit aufgeben müssen, Delphis Typsystem erlaubt das einfach nicht.
Edit: Um die Sache mit der Kovarianz auszuführen: Gäbe es diese in Delphi, könntest du in der Basisklasse lesend auf die Liste zugreifen. Hineinschreiben wäre in keiner Sprache typsicher. |
AW: Generics und Vererbung
Zitat:
Beispiel:
Delphi-Quellcode:
Laut der
var
list1: TList<TObject>; list2: TList<TPersistent>; begin list1 := list2; // <- E2010 Incompatible types: 'Generics.Collections.TList<System.TObject>' and 'Generics.Collections.TList<Classes.TPersistent>' ![]() Also kann ich ohne Probleme folgendes machen:
Delphi-Quellcode:
list1 := TList<TObject>(list2);
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:10 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