AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Generics und Vererbung

Ein Thema von Codewalker · begonnen am 31. Aug 2011 · letzter Beitrag vom 31. Aug 2011
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Codewalker
Codewalker

Registriert seit: 18. Nov 2005
Ort: Ratingen
945 Beiträge
 
Delphi XE2 Professional
 
#1

Generics und Vererbung

  Alt 31. Aug 2011, 15:03
Delphi-Version: XE
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:
  TDirectedEdgeList<T, V> = class(TList < TDirectedEdge < T, V >> );
  TEdgeList<T, V> = class(TList < TEdge < T, V >> );
Durch diese "doppelte" Verschachtelung bin ich jetzt überfragt, wie ich eine TBasicEdgeList konstruieren kann, von denen die beiden anderen Klassen abgeleitet sind.



Edit: Eine Idee wäre den konkreten Datentyp als dritten generischen Parameter mitzugeben und über Constraints entsprechend einzuschränken.

Delphi-Quellcode:
  TBasicEdgeList<T, V, ET: TBasicEdge<T, V>, constructor> = class(TList < ET < T, V >> );
  TDirectedEdgeList<T,V> = class(TBasicEdgeList<T,V,TDirectedEdge<T,V>>);
Das scheitert aber schon an der ersten Deklaration: "Undeklarierter Bezeichner: 'ET<,>' "

Geändert von Codewalker (31. Aug 2011 um 15:18 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.034 Beiträge
 
Delphi 12 Athens
 
#2

AW: Generics und Vererbung

  Alt 31. Aug 2011, 15:25
<ET: TBasicEdge> geht halt nicht. Man kann nur sowas sagen, wie record oder class.
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>>
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Codewalker
Codewalker

Registriert seit: 18. Nov 2005
Ort: Ratingen
945 Beiträge
 
Delphi XE2 Professional
 
#3

AW: Generics und Vererbung

  Alt 31. Aug 2011, 15:32
Ganz so klappt es nicht, aber du hast mich auf die richtige Idee gebracht. class muss weg, weil sonst meckert der Compiler in der vererbten Klasse, es wäre kein Klassentyp . Die direkte Zuweisung über das Gleichheitszeichen mag er auch nicht. Mit ein bißchen basteln, kommt man dann aber auf eine funktionierende Lösung:

Delphi-Quellcode:
  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 >> );
Sieht zwar aus wie ein Klammerirrgarten, aber scheint genau das zu tun, was es soll.

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

Geändert von Codewalker (31. Aug 2011 um 15:35 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.034 Beiträge
 
Delphi 12 Athens
 
#4

AW: Generics und Vererbung

  Alt 31. Aug 2011, 15:41
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
?
Delphi-Quellcode:
  TBasicGraph<E, V> = class
  private
    FEdges: TBasicEdgeList<E, V, TBasicEdge<E, V>>;
Wenn du diesen Typen nicht schon type TBasicEdgeList<...> = class( {hier} ); benötigen würdest, dann wäre ein Subtype möglich gewesen.
Delphi-Quellcode:
  TBasicGraph<E, V> = class
  private
    type TMyBasicEdge = TBasicEdge<E, V>;
    ...
  end;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Codewalker
Codewalker

Registriert seit: 18. Nov 2005
Ort: Ratingen
945 Beiträge
 
Delphi XE2 Professional
 
#5

AW: Generics und Vererbung

  Alt 31. Aug 2011, 15:49
Delphi-Quellcode:
  TBasicGraph<E, V> = class
  private
    FEdges: TBasicEdgeList<E, V, TBasicEdge<E, V>>;
Genau so habe ich es auch versucht. Die Fehlermeldung die ich dabei bekomme ist schon fast sehenswert:
"[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:
  { 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;
Für die jeweiligen Graphenklassen TDirectedGraph<E, V> und TUndirectedGraph<E, V> wollte ich eine gemeinsame Oberklasse TBasicGraph<E, V> einführen, weil die ja ziemlich viel gemeinsam haben. Diese sollte TBasicGraph<E, V> heißen. Die Kanten selbst werden in einer einfachen Liste verwaltet. Das waren bisher die Typen TDirectedEdgeList<T,V> und TEdgeList<,V> . In der Elternklasse TBasicGraph<E, V> muss ich diese Liste jetzt irgendwo als privates Attribut anlegen, erstellen, usw.

Das sieht im Moment so aus:
Delphi-Quellcode:
  TBasicGraph<E, V> = class
  private
   FEdges: TBasicEdgeList<E, V, TBasicEdge<E, V>>;
  {...}
Wenn ich jetzt versuche, FEdges mit einem konkreten Typen zu erstellen  FEdges := TDirectedEdgeList<E, V>.Create() bekomme ich diese nette und übersichtliche Fehlermeldung von oben.
  Mit Zitat antworten Zitat
USchuster

Registriert seit: 12. Sep 2010
Ort: L.E.
120 Beiträge
 
Delphi XE3 Professional
 
#6

AW: Generics und Vererbung

  Alt 31. Aug 2011, 16:37
<ET: TBasicEdge> geht halt nicht. Man kann nur sowas sagen, wie record oder class.
Auf eine bestimmte Klasse kann man (bescheuerter Weise) keinen Typen einschränken.
Das kann ich nicht nachvollziehen mit D2009, D2010 und XE.
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.
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#7

AW: Generics und Vererbung

  Alt 31. Aug 2011, 17:21
<ET: TBasicEdge> geht halt nicht. Man kann nur sowas sagen, wie record oder class.
Auf eine bestimmte Klasse kann man (bescheuerter Weise) keinen Typen einschränken.
Das kann ich nicht nachvollziehen mit D2009, D2010 und XE.
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.
Diesen Unfug erzählt Himitsu schon eine Weile lang und es stimmt einfach nicht. Das einzige, was vor XE(?) nicht ging (ka, welche QC Nummer), war, dass ein type constraint auf eine Klasse nicht den constructor constraint mit beinhaltete und demnach bei einem T.Create meckerte (oder sowas ähnliches)
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.034 Beiträge
 
Delphi 12 Athens
 
#8

AW: Generics und Vererbung

  Alt 31. Aug 2011, 18:18
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.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Khabarakh
Khabarakh

Registriert seit: 18. Aug 2004
Ort: Brackenheim VS08 Pro
2.876 Beiträge
 
#9

AW: Generics und Vererbung

  Alt 31. Aug 2011, 18:45
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.
Sebastian
Moderator in der EE

Geändert von Khabarakh (31. Aug 2011 um 18:47 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#10

AW: Generics und Vererbung

  Alt 31. Aug 2011, 20:55
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.
Wenn du weißt, dass es sich um Kovarianz handelt, kannst du mit einem Hardcast "nachhelfen".

Beispiel:
Delphi-Quellcode:
var
  list1: TList<TObject>;
  list2: TList<TPersistent>;
begin
  list1 := list2; // <- E2010 Incompatible types: 'Generics.Collections.TList<System.TObject>' and 'Generics.Collections.TList<Classes.TPersistent>'
Laut der Definition sind diese beiden Listen aber kovariant.
Also kann ich ohne Probleme folgendes machen: list1 := TList<TObject>(list2);
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:02 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