Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Zirkuläre Unit Reference (https://www.delphipraxis.net/81293-zirkulaere-unit-reference.html)

Koolance 24. Nov 2006 15:08

Re: Zirkuläre Unit Reference
 
Nachdem ich zunächst dachte alle wird gut, musste ich feststellen das nur die geerbten Methoden und Eigenschaften übernommen werden :( (bei den Anderen Fehlermeldung: "Undefinierter Bezeichner")

Also habe ich zum test nicht mehr geerbt, nun kriege ich aber die Fehlermeldung: "Typ ... nicht vollständig definiert"

Die Fehlermeldung lässt sich so umgehen:
Delphi-Quellcode:
type
  TClass1 = class end;

  TClass2 = class
    FClass1: TClass1;
  end;

  TClass1 = class
    FClass2: TClass2;
  end;
Aber so sieht Delphi die Klasse leider als leere Klasse und ich kriege die Fehlermeldung: "Undefinierter Bezeichner"

Sidorion 24. Nov 2006 15:48

Re: Zirkuläre Unit Reference
 
ohne das end bei der Forward-Deklaration. Sonst denkt Delphi, die Klasse ist komplett, also so:
Delphi-Quellcode:
Type
  TFoo=Class;
 
  TBar=Class
   FFoo: TFoo;
  End;

  TFoo=Class
   FBar: TBar;
  End;

Koolance 24. Nov 2006 16:04

Re: Zirkuläre Unit Reference
 
Liste der Anhänge anzeigen (Anzahl: 1)
Das habe ich ja schon probiert. Passend zu dem Quelltext käme jetzt: Typ TFoo nicht vollständig definiert.

Ich habe ein kleines Beispiel gemacht.

xaromz 24. Nov 2006 21:50

Re: Zirkuläre Unit Reference
 
Hallo,

ich habe Dir schon in meinem letzten Beitrag geschrieben, wie es geht. In Deinem Beispielcode deklarierst Du die beiden Klassen in verschiedenen Units, bzw. schreibst in der einen Unit eine Forward-Deklaration auf eine Klasse in einer anderen Unit. Das funktioniert natürlich nicht. Wenn Du Forward-Deklaration nutzt ("type TFoo = class;"), dann musst Du diese Klasse auch komplett in dieser Unit deklarieren.

Gruß
xaromz

negaH 25. Nov 2006 08:19

Re: Zirkuläre Unit Reference
 
Präziser:

Forward Deklarationen eines Types müssen im gleichen "Type" Block erfolgen samt ihrer vollständigen Deklaration. Ein regülärer Bezeichner auf Unitebene beendet eines Type Block automatisch. Ein regulärer Unitbezeichner sind "Unit", "uses", "implementation" und "interface". Ergo: mit Delphi gehen keine Forward Deklarationen über Unitgrenzen hinweg, noch in unterschiedlichen Type-Blöcken.

Erweitere mal virtuell in Gedanken alle Sachen wie "const", "type", "implementation", "interface" nit einem sofortigem "begin end;" Block. Denn defakto existieren diese quasi im Compiler auch wenn wir sie nicht im Source schreiben müssen/dürfen. Dh. nach einem "type" stände sofort "begin end;" und dazwischen kannst du Forward Deklaration machen wie du möchtest Hauptsache du deklarierst diese Typen dann in diesem Block auch vollständig. Eine Deklaration innerhalb dieses "virtuellen" Bereiches ist nicht in anderen "Bereichen" sichtbar.

Einzigste Ausnahme speziell auf den Bezeichner "type" bezogen ist die Deklaration eines neuen eigenständigen Standarddatentyps abgeleitet von einem anderen Datentyp, also sowas:

Delphi-Quellcode:

type
//begin

   TTime = type TDateTime;
   TDate = type TDateTime;

   MyInteger = type Integer;

//end;

type
//begin

//end;
Gruß Hagen

Koolance 27. Nov 2006 14:28

Re: Zirkuläre Unit Reference
 
Liste der Anhänge anzeigen (Anzahl: 1)
Das Problem ließ sich mit noch ein bisschen externer hilfe lösen.
Es müssen zu den einzelnen Klassen Interfaces erstellt, und in einzelne Units gepackt werden.
Ich habe für ein Beispiel geschrieben und für alle Interessierten in den Anhang gepackt.

@xamroz
Mein Problem war das es mir sehr wichtig ist die Unitunterteilung aufrecht zu erhalten. Ich dachte es wäre so möglich...

xaromz 27. Nov 2006 16:01

Re: Zirkuläre Unit Reference
 
Hallo,
Zitat:

Zitat von Koolance
Das Problem ließ sich mit noch ein bisschen externer hilfe lösen.
Es müssen zu den einzelnen Klassen Interfaces erstellt, und in einzelne Units gepackt werden.
Ich habe für ein Beispiel geschrieben und für alle Interessierten in den Anhang gepackt.

Ich hoffe, Du weißt, was Du da tust. Interfaces sind eine sehr fehlerträchtige Sache. Insbesondere durch die gegenseitige Abhängigkeit der beiden Interfaces wirst Du vermutlich ein Speicherleck bekommen. Für diesen Zweck sind Interfaces

Zu Deinem Demoprogramm:
- Du castest ein Interface auf das zugrundeliegende Objekt. Das ist nicht zulässig.
- Du benutzt Objekte, ohne Instanzen zu erzeugen. Das fliegt Dir bald um die Ohren.

Gruß
xaromz

negaH 27. Nov 2006 16:22

Re: Zirkuläre Unit Reference
 
Neben den korrekten Bemerkungen von Xaromz noch als Bemerkung zusätzlich:

Das was du in deinem Testprojekt machts geht auch einfacher

Delphi-Quellcode:

unit class1;

interface

type
  TClass1 = class
  private
    FClass2: TObject;
  public
    procedure BlaBla;
  end;

implementation

uses class2;

procedure TClass1.BlaBla;
begin
  (FClass2 as TClass2).BlaBla;
end;

unit class2;

interface

type
  TClass2 = class
  private
    FClass1: TObject;
  public
    procedure BlaBla;
  end;

implementation

uses Class1;

procedure TClass2.BlaBla;
begin
  (FClass1 as TClass1).BlaBla;
end;
Gruß hagen

Koolance 27. Nov 2006 17:00

Re: Zirkuläre Unit Reference
 
Dieser Weg soll der sauberere sein, die andere Möglichkeit wäre alles von einem Basisobjektabzuleiten, dann statt dem Interface über das Basisobjekt die Typen zu deklarieren, und am ende wie bei dem Interface zu casten.

@xaromz
[qoute]Ich hoffe, Du weißt, was Du da tust. Interfaces sind eine sehr fehlerträchtige Sache. Insbesondere durch die gegenseitige Abhängigkeit der beiden Interfaces wirst Du vermutlich ein Speicherleck bekommen. Für diesen Zweck sind Interfaces [/quote]

Ich werde wie gesagt den Quellcode erzeugen, also muss ich es nur einmal richtig hin bekommen, und alle interfaces sind richtig.

Zitat:

- Du castest ein Interface auf das zugrundeliegende Objekt. Das ist nicht zulässig.
- Du benutzt Objekte, ohne Instanzen zu erzeugen. Das fliegt Dir bald um die Ohren.
Warum ist das casten unzulässig?
In meinem echten Projekt werden selbst verständlich alle Objekte instanziiert.

@NegaH
Du leitest statt von dem Interface von TObject ab, habe heute keine Zeit mehr das zu testen, werde ich aber auch ausprobieren. Hat es Nachteile?

negaH 28. Nov 2006 00:10

Re: Zirkuläre Unit Reference
 
Nein, hat keine Nachteile (mein Vorschlag oben), mal davon abgesehen das deine ganze Objektorientierte Konstruktion insich falsch sein muß.

Wenn du über solche Sachen wie oben mein Typcast oder den Interfaces herangehen musst dann stimmt irgendwas nicht an deinem Grundkonzept.

Xaromz hat aber insofern Recht, das

1.) der Weg über die Interfaces ein unnötiger Überbau darstellt da wie in meinem Beispiel das Ganze auch ohne Interfaces geht
2.) du die Verwendung von Interfaces und Klassen nicht vermischen solltest da ansonsten das automatische Referencecounting und somit die Speicherfreigabe durcheinander kommt
3.) der Typcast eines Interfaces direkt in das implementierende Objekt in deinem Source vollkommen falsch ist
4.) der Typcast eines Interfaces in sein implementierendes Objekt grundsätzlich gegen die Regeln, bzw. dem Sinn der Interfaces ist

Wenn du schon eine Referenz von einem Interface auf sein implementierendes Objekt erhalten möchtest dann so:

Delphi-Quellcode:

type
  IMyInterface = interface
    function Implementor: TInterfacedObject;
  end;

  TMyImplementor = class(TInterfacedObject, IMyInterface)
    function Implementor: TInterfacedObject;
  end;

function TMyImplementor.Implementor: TInterfacedObject;
begin
  Result := Self;
end;

// oder gleich so, da Result -> EAX und Self -> EAX
function TMyImplementor.Implementor: TInterfacedObject;
begin
end;
Aber!! zum Widersinnigen der Sache:

Interfaces sollen die Implementierung einer Funktionalität im Zusammenhang mit dessen Schnittstellen Deklaration vollständig voneinander trennen. Es soll also keinerlei Zusammenhang zwischen einer deklarierten Schnittstelle zu der eigentlichen Implementierung dieser Schnittstelle bestehen, vollkommene Abstraktion der verschiedenen Schichten eines Denkmodelles das zur "idealen" Black Box führt.

Führt man aber wie oben in die Schnittstelle = Interface wieder eine Schnittstelle auf den Implementor-> TMyInterfcae ein so durchbricht man diese strikte Logik und macht die Anwendung der Interfaces sinnnlos.

Denn die Deklaration von IMyInterface oben bedeutet das diese Schnittstelle nur durch ein Objekt kompatibel zur Klasse TInterfacedObject durchgeführt werden kann. Diese Restriktion soll aber gerade mit Interfaces strikt vermieden werden.

Ergo: ein normaler OOP Ansatz wie in meinem letzten Posting erreicht exakt das Gleiche wie der Vorschlag über die Interfaces. Nur mit dem Unterschied

1.) das es Typsicher ist und somit sauber, wir eben keinen harten und typ-unsicheren Cast verwenden wie in deinen Sourcen
2.) ohne Umwege funktioniert und somit zusätzliche Fehlerquellen beseitigt. Bedenke die schlimmsten Fehler liegen immer im Konzept eines Modelles !
3.) kein Hilfsmittel misbraucht das für ganz andere Aufgaben gedacht ist, hier eben die Interfaces, und somit die spätere Verwenung deines Modelles für andere "korrekt denkende" Programmierer unmöglich macht. Denn für diese Programmierer ist es ein Unding wie du Interfaces mißbrauchen möchtest.

Grundsätzlich wird man aber deine Problemstellung durch pure OOP und konzeptionelle Änderungen lösen können. Statt mit 2 Units zu arbeiten musst du OOP konform dein Klassenkonzept umstellen und mit 3 Unit arbeiten.

1. Unit -> Basisunit die eine abstrakte Vorfahrklasse enthält in der alle Gemeinsamkeiten der Nachfahrklassen deklariert wurden, meistens abstrakte Klassen. Sprich Klassen aus reiner Deklaration von abstrakten virtuellen Methoden ohne reale Implementierung.

2. Unit -> Nachfahre Class1 von der Basisklasse und Verwendung von UnitClass2 in der Implementation Sektion dieser Unit.

3. Unit -> Nachfahre Class2 von der Basisklasse und Verwendung von UnitClass1 in der Implementation Sektion dieser Unit.

Zitat:

Dieser Weg soll der sauberere sein,...

Ich werde wie gesagt den Quellcode erzeugen, also muss ich es nur einmal richtig hin bekommen, und alle interfaces sind richtig.
Wenn du davon überzeugt bist warum fragst du dann noch ? Ich meine, und damit bin ich nicht der Einzigste hier, das du mit dieser Meinung schon von vornherein deinen größten Fehler begehst. Begründungen siehe oben.

Gruß hagen


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:10 Uhr.
Seite 2 von 3     12 3      

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