![]() |
Trick um "überkreuzenden Bezug" von Units zu umgeh
kennt irgendjemand eine clevere Möglichkeit um nicht Haufen Umwege gehen zu müssen ?
Ich habe zwei Objecte in zwei verschiedenen Units. Und will von jedem Object einen Zeiger auf das andere Object speichern können. in Unit1:
Code:
in Unit2:
TClass1 = class
p : TClass2; end;
Code:
dummerweise muss ich nun in Unit2 die Unit1 in den Uses Klauseln einfügen und umgekehrt.
TClass2 = class
p : TClass1; end; Dummerweise kommt ja nun die Meldung "Überkreuzender Bezug zweier Units" HAb schon einige ZEit gegrübelt, kann man das irgendwie über eine dritte Unit umgehen ? Forward Deklarationen ? mir is noch keine Lösung eingefallen ? will nich immer mit:
Code:
arbeiten .. ständig die Zeiger beim programmieren zu typisieren macht auch keine Laune !
TClass2 = class
p : TObject; end; Dankeschön ! |
Re: Trick um "überkreuzenden Bezug" von Units zu u
es kommt zwar drauf an was du genau machen möchtest. Aber mit einer 3ten Unit würde das schon gehen.
In Unit 1 und Unit2 jeweils ein uses auf Unit3 in Unit 3 ein Uses auf Unit1 und Unit2. Nun in dieser Unit die beiden Variablen deklarieren: var p1 : TClass1; var p2 : TClass2; Nun kannst du in Unit1 das Object p2 verwenden und in Unit2 das Object p1 (erzeugen nicht vergessen :) ) vielleicht hab ich dich auch ganz falsch verstanden... |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Das müsste auch gehen, wenn du z.B. in Unit1 die andere direkt in die Uses einfügst und in Unit2 nach implementation nochmal uses Unit1; schreibst :wink:
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
²jfheins: Das wird vermutlich nicht gehen, da die Klassendeklarationen (in denen man den Bezug auf die jeweils andere Unit ja schon benötigt) wohl im Interface-Teil stehen werden..
:arrow: Ohne Globale Variablen *pfui* oder der TObject-Methode, die Du selbst schon angesprochen hast, siehts imho schlecht für Dich aus! Gruß Stephan :dance: |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Moin Stoxx,
oder Du musst beide in einer Unit deklarieren.
Delphi-Quellcode:
type
TClass1 = class; TClass2 = class F2 : TClass1; end; TClass1 = class F1 : TClass2; end; |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Hallo An Alle,
@Maa83 .. da geht natürlich nicht, da man dort ja wieder den überkreuzenden bezug von Unit1/Unit3 und umgekehrt hat. @jfheins .. ich brauch ja aber die Unit1 schon im interface Teil, das is ja gerade der Witz ;-) @Christian .. so hab ichs nun auch gemacht. Dennoch kann ich ein Gesamtes Programm nich in einer Unit unterbringen ;-) is auf Dauer halt sehr sehr schlecht ... aber scheint wohl doch nicht zu gehen. habe D7 .. Ist das mit Delphi 8 / Delphi9 möglich sowas ? |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
Weil man den Überblick verlieren könnte, wo sie in welcher Unit geändert werden könnten oder was? Echt neugierig! mfg |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Nunja, ganz kurz und knapp gesagt: Mangelnde Übersichtlichkeit, mangelnde Kontrolle ( :!: z.B. muss der Programmierer wissen, wann die Variable welche Werte annehmen kann, von wo aus sie geändert werden kann etc.); häufig ist damit eine unnötige Belegung von Speicherplatz verbunden; und vor allem widerspricht das allgemein der Idee des OOP, und innerhalb der OOP wiederum widersprächen (wenn sie denn generell mit oop vereinbar wären :mrgreen: ) globale Variablen dem Geheimnisprinzip... Hinzu können Namenskonflikte kommen
Wie gesagt, Kurzfassung :mrgreen: Gruß Stephan :dance: |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
Bei schwacher Kopplung wäre das Observer-Visitor Design Pattern interessant: ![]() ![]() Oder eher umgekehrt: das Observer Pattern führt zu einer schwachen Kopplung zwischen den Objekten. |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Ist auch mit einem Zeiger lösbar:
Unit1.pas:
Delphi-Quellcode:
interface
uses Unit2; TClass1 = class i: Integer; p: TClass2; end; Unit2.pas:
Delphi-Quellcode:
interface
TClass2 = class p: Pointer; end; implementation uses Unit1; procedure foo(); begin TClass1(p).i := 17; end; |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Genau das will er ja nicht machen.
Imho ist die einzige saubere Lösung der Umweg über eine 3. Unit die nur die Deklaraktionen enthält. Zitat:
Delphi-Quellcode:
unit Unit3;
. . type TClass2 = class; TClass1 = class p: TClass2; end; TClass2 = class p: TClass1; end;
Delphi-Quellcode:
unit Unit1;
uses Unit3...
Delphi-Quellcode:
und fertig ;)
unit Unit2;
uses Unit3... |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Hi dizzy,
es bleibt dabei, dass ich halt in Unit3 alle Implementationen integrieren muss. Von beiden Objecten. Und das is halt nich schön.. |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Also ich halte das eigentlich für besonders schön, da man dadurch sehr nett modularisiert. Wenn du auf einmal einen der Typen in einer weiteren Unit brauchst, reicht es die deklarierende Unit einzubinden, und du kommst nie in die Verlegenheit von Kreuzbezügen. Ich habe mir mittlerweile angewöhnt jede Klasse in eine eigene Unit zu packen bzw. sehr eng verwandte. Das eigentliche Programm hingegen enthält nur die Klassendefinition "TForm1", alles weitere wird "ge-used".
Bin damit bisher sehr gut gefahren, und die Übersichtlichkeit gewinnt zudem :). Gruss, Fabian |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
Vielleicht kann einer noch mal ein Beispiel posten. Ich habe zwei Klassen, in deren Interface-Teil muss jede auf die jeweils andere verweisen. Methoden gibt's natürlich auch. Die Implementation soll in eigenen Units erfolgen. Benutze Delphi 7. Vielen Dank, dartrax |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Du könntest das mit einem Interface lösen. In einem Interface werden nur die Funktionen und Properties definiert. keine Implementierung davon. Deine Klassen TClass1 und TClass2 erweitern das Interface nur, bzw. müssen die im Interface deklarierten Funktionen implementieren. Schau die das mit den Interfaces in der Online-Hilfe an.
Grobes Gerüst: Unit3:
Delphi-Quellcode:
In Unit1 dann:
IClass1 = interface
Procedure Proc1(parameter...); Procedure Proc2(parameter..); end; IClass2 = Interface Procedure TueWas(parameter..); Procedure TueWasAnderes(..); end;
Delphi-Quellcode:
In Unit2 dann analog zur Unit1:
uses Unit3;
TClass1 = class(TObject, IClass1) p2: IClass2; Procedure Proc1(parameter...); Procedure Proc2(parameter..); end; impelementation Procedure TClass1.Proc1(paramemeter...); begin end; ...
Delphi-Quellcode:
uses Unit3;
TClass2 = class(TObject, IClass2) p2: IClass1; Procedure TueWas(parameter..); Procedure TueWasAnderes(..); end; impelementation Procedure TClass2.TueWas(paramemeter..); begin end; ... Ich denke so in etwa müsste das funktionieren, bin mir allerdings nicht ganz sicher. In Unit3 brauchst du keine implementierung zu den Funktionen schreiben. Habe das nicht ausprobiert. Schau halt in der Hilfe nach wie genau das geht. rantanplan |
Re: Trick um "überkreuzenden Bezug" von Units zu u
die antwort von rantanplan99 ist am sinnvollsten, da unit3 nur die interfaces bestimmt.
wenn du die beiden klassen benutzen moechtest, wuerde ich dir empfehlen, nur ueber die schnittstelle auf die objekte zuzugreifen. innerhalb der objekte geht ja ohnehin nichts mehr anderes. warum muss eigentlich ein kreuzbezug zwischen den beiden klassen bestehen? |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Einfachste und sauberste Lösung:
Forward-Deklaration von TClass2 Deklaration von TClass1 Deklaration von TClass2 Alles in eine Unit packen. Anders geht's nicht! |
Re: Trick um "überkreuzenden Bezug" von Units zu u
naja, das ganze laesst aber auf einen design-fehler schliessen, wenn ich einen kreuzbezug erzeuge. es wuerde mich schon interessieren, warum er hier von noeten ist.
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Dann wär die VCL ein einziger Designfehler: Dort wird in TControl bereits auf TWinControl verwiesen, und ähnliches.
Forward-Deklarationen sind von daher gesehen in vielen Situationen sogar seh nützlich. @Möglicher Designfehler: Probleme bei der Hierarchie der Komponentenvererbungen, d.h. keine eindeutigen Vererbungen und Datenflüsse. |
Re: Trick um "überkreuzenden Bezug" von Units zu u
innerhalb einer unit ist es in ordnung. dass war ja auch dein loesungsvorschlag. er hat aber einen kreuzbezug zweier units. das wuerde mich interessieren.
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Hallo!
Ich habe es jetzt mit der Idee mit den Interfaces von rantaplan gemach. Ohne, dass ich eine "Unit3" benötige. Trotzdem würde mich interessieren, wie dizzys Lösung dieses Problem umschifft; ich habe das folgende Beispiel doch genau so gemacht, wie es gedacht ist mit der zusätzlichen Unit, oder?
Delphi-Quellcode:
unit Unit1;
interface uses Unit3; implementation procedure TClass1.DoOneThing(Class2: TClass2); begin // I'm really busy end; end.
Delphi-Quellcode:
unit Unit2;
interface uses Unit3; implementation procedure TClass2.DoAnotherThing(Class1: TClass1); begin // That's too much for me end; end.
Delphi-Quellcode:
Jetzt meckert der Compiler wegen ungenügenden Forward- oder External-Deklarationen in Unit3 - Logisch, die Implementierun findet ja in den ursprünglichen Units statt. Trotzdem wurde das Problem von niemandem hier erwähnt. Wenn ich nun im implementation-Teil von Unit3 ein Uses auf die ursprünglichen Units setze:
unit Unit3;
interface type // Forward-deklarationen aller Klassen TClass1 = class; TClass2 = class; // Vollständige Deklaration Class 1 TClass1 = class private // Verweis auf Class 2 Class2: TClass2; public // Irgendeine Methode procedure DoOneThing(Class2: TClass2); end; // Vollständige Deklaration Class 2 TClass2 = class private // Verweis auf Class 1 Class1: TClass1; public // Irgendeine Methode procedure DoAnotherThing(Class1: TClass1); end; implementation end.
Delphi-Quellcode:
kommt der Fehler natürlich nicht mehr, jedoch mag der Compiler nun in den ursprünglichen Units die Implementierungen nicht mehr - was ich nicht nachvollziehen kann.
implementation
uses Unit1, Unit2; end. Ob der Kreuzbezug richtig ist oder nicht möchte ich hier nicht zur Diskussion stellen - ich schließe mich da der Meinung von BenBe an. dartrax |
Re: Trick um "überkreuzenden Bezug" von Units zu u
hier noch eine moeglichkeit mit interface
Delphi-Quellcode:
dann die beiden implementierunsklassen
unit UInterfaces;
interface type IKlasse1 = interface function tellName(): string; function doSomething(): string; end; IKlasse2 = interface function tellName(): string; function doSomething(): string; end; implementation end. Klasse 1
Delphi-Quellcode:
Klasse 2
unit UKlasse1;
interface uses ComObj, UInterfaces; type TKlasse1 = class(TComObject, IKlasse1) public InterfaceZurKlasse2: IKlasse2; function tellName(): string; function doSomething(): string; constructor Create; end; implementation constructor TKlasse1.Create(); begin end; function TKlasse1.tellName(): string; begin Result := 'Bin Klasse1'; end; function TKlasse1.doSomething(): string; begin Result := 'Bin in Klasse1 und rufe jetzt Klasse2 auf: '; if not(InterfaceZurKlasse2 = nil) then Result := Result + InterfaceZurKlasse2.tellName() else Result := Result + 'Ups, nix da!!'; end; end.
Delphi-Quellcode:
und die anwendung
unit UKlasse2;
interface uses ComObj, UInterfaces; type TKlasse2 = class(TComObject, IKlasse2) public InterfaceZurKlasse1: IKlasse1; function tellName(): string; function doSomething(): string; constructor Create; end; implementation constructor TKlasse2.Create(); begin end; function TKlasse2.tellName(): string; begin Result := 'Bin Klasse2'; end; function TKlasse2.doSomething(): string; begin Result := 'Bin in Klasse2 und rufe jetzt Klasse1 auf: '; if not(InterfaceZurKlasse1 = nil) then Result := Result + InterfaceZurKlasse1.tellName() else Result := Result + 'Ups, nix da!!'; end; end.
Delphi-Quellcode:
so ungefaehr eben ;o)
unit UMain;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, UKlasse1, UKlasse2, UInterfaces, StdCtrls; type TForm1 = class(TForm) Memo1: TMemo; procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var Klasse1: TKlasse1; Klasse2: TKlasse2; InterfaceKlasse1: IKlasse1; InterfaceKlasse2: IKlasse2; begin Klasse1 := TKlasse1.Create(); Klasse2 := TKlasse2.Create(); Klasse1.InterfaceZurKlasse2 := Klasse2; Klasse2.InterfaceZurKlasse1 := Klasse1; Memo1.Clear(); Memo1.Lines.Add(Klasse1.doSomething()); Memo1.Lines.Add(Klasse2.doSomething()); end; end. |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
Einfacher ist in dem Moment relativ. Ich persönlich finde es grob unsauber und unhadlich wenn:
Einfach mal einen Blick in Classes.pas werfen. Dann sieht man sehr schnell wie einfach man sich mit Forward declares beide Hände fesselt und die Units ins grenzenlose wachsen lassen. :roll: Nobodys Weg zeigt absolut in die richtige Richtung. Zwei Möglichkeiten dazu findet man hier: ![]() @Nobody, statt TComObject wären TInterfacedObject, TContainerObject oder TAggregatedObject bessere Basisklassen für die Implementierung von Interfaces. ;) (Außerdem werden sie schon in System deklariert :) ) |
Re: Trick um "überkreuzenden Bezug" von Units zu u
@robert: hab schon lange nicht mehr in delphi entwickelt, deswegen hab ich das erstbeste genommen. hast aber recht :o)
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
Zitat:
Die VCL enthält meiner Meinung nach fast keine OOP Designschwächen in ihrer Klassenhierarchie. Gruß hagen |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zitat:
|
Re: Trick um "überkreuzenden Bezug" von Units zu u
Zum ursprünglichen Problem:
Zitat:
Nachdem ich heute die neue Version von ![]() Wie wäre es mit Chrome? Das kennt diese Probleme dank eines modernen Compilers nicht mehr. Im Gegensatz zu Delphi.Net kann man in Chrome namespaces so verwenden wie sie gedacht waren. (Und muss sich nicht weiterhin mit Dateinamen nerven lassen :wall: ) Die Dateinamen sind absolut unerheblich ;) Erste Datei:
Delphi-Quellcode:
Zweite Datei:
namespace EinNamespace;
interface type Class1 = public class private fClass2 :Class2; public property Class2 :Class2 read fClass2; end; implementation end.
Delphi-Quellcode:
Beide Klassen sind im gleichen Namespace deklariert und man muss rein gar nichts rumbasteln, rumschrauben oder sonstwas umbiegen.
namespace EinNamespace;
interface type Class2 = public class private fClass1: Class1; public property Class1 :Class1 read fClass1; end; implementation end. Ich meine genau so sollte es doch sein. :) Sicher ist es in solchen Fällen oftmals handlicher gewisse Abstraktionen auf das Wesentliche zu machen. Aber wenn man es macht, dann nur weil man es will, nicht weil der Compiler zu antiquiert ist. ;) *Ich fand es übrigens so gut, dass ich es nach 15 Minuten testen gleich gekauft habe. Nach all den Face lifts seit meiner vorherigen ur-alt-beta Version erscheint mir Chrome sogar mächtiger als C#, hat alle IMHO sinnlosen Beschränkungen von Delphi über Board geworfen. Aber trotzdem diese schlichte Eleganz bewahrt, die Pascal auszeichnet... |
Re: Trick um "überkreuzenden Bezug" von Units zu u
Hi Robert,
Chrome werde ich mir bei Gelegenheit mal angucken. Ich habe zwar die Vorzüge von .NET erkannt, bin aber noch nicht umgestiegen :-) im Moment wäre das zuviel Arbeit. ABER, was die Sache mit den Überkreuzdeklarationen angeht, habe ich mich entschlossen, den Entwurf überhaupt nicht weiterhin so gestalten zu wollen. Strebe jetzt strenge Baumhierarchien von OBEN nach UNTEN an. Gegenseitige Objektbekanntschaften vermeide ich, indem ich die Kommunikation von UNTEN nach OBEN ganz normal über Objektreferenzen löse, aber umgekehrt von OBEN nach UNTEN nur noch versuche EVENTS zu nutzen. Somit müssen die Klassen, die in der "Hierarchie" oben stehen, überhaupt keine Objectreferenz mehr haben. Damit entfällt auch das Problem der Überkreuzdeklaration. Ausserdem auch viel besser wegen Quelltextwiederverwendbarkeit, gegenseitige Abhängigkeiten und so theoretischen Zeugs ;-) Und wenn ichs in Notfällen wirklich mal brauche, werde ich weiterhin rumcasten :-D bis denn dann |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:15 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