Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Überkreutzer Aufruf von Units: Wie kann ich es umgehen?


mimi - Di 07.10.03 19:13
Titel: Überkreutzer Aufruf von Units: Wie kann ich es umgehen?
Hallo,

ich hab folgenden code: (steht in einer unit drin)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
type
TTest1 = class(TThread)
  private
    { Private-Deklarationen }
  protected
    procedure Execute; override;

  public
    FSound:TSound;
    constructor Create(ACreateSuspended: Boolean; Sound: TSound);

  end;

steht in einer andren unit drin:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
type
  TSound = class
    private
      GoFlag:Integer;
      test:TTest1;
      
    protected

    public
      PlayListe: array of TPlayListe;
      Random_Music: array of TPlayListe;
      laden,noTime:Boolean;
      AIndex:Integer;
      constructor create(pSoundFiles,SoundDir,DefaultExt:String;flag:Integer); // Lädt die Angebenden Sound Files
      procedure StopMusic; // stop alles geladene musik dateien.
      procedure NewMusik;
      procedure NewMusik2;
      procedure LoadMusikFile(Index:Integer;RM:Boolean);
      procedure AddPlayListe(FileName:String); // Fügt der Playliste eine Datei hinzu
      procedure PlayMusikFile(Index:Integer);
  end;

jetzt brauche ich die erste klasse in der zweiten unit und die zweite klasse in der ersten unit, wie bekomme ich es hin? egal was ich mache es kommt immer zu den gleichen compiler fehler:
Zitat:
[Fataler Fehler] soundsystem.pas(10): Überkreuzender Bezug zweier Units auf 'soundsystem'


Moderiert von user profile iconTino: Topic verschoben; Quote-Tags hinzugefügt.


Anonymous - Di 07.10.03 19:16

du musst beide Klassen in eine Unit schreiben, dann gehst. Eventuell brauchst du noch eine Forwarddeklaration einer der Klassen, ich habs mir jetzt nich genau angeguckt.

Alternativ kannst du auch nach implementation ein weiteres uses einfügen und dort die andere Unit einbinden. In diesem Fall dann in der Unit von TSound, weil du TTest1 nicht in der deklaration von TSound benutzt.


mimi - Di 07.10.03 19:18

diesen möglichkeit habe ich auch versucht, ging aber auch nicht, weil beide klassen brauchen sich gegenseitig, aber den ein tipp kann ich mal testen.

geht auch nicht, weil ich eine variable habe bei der crate funktion habe ich es hinzugefügt(Forward) :(


Keldorn - Di 07.10.03 19:23

wenn du es in einer unit schreibst:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
type 
   //vorwärtsdeklaration
  TTest1 = class;
  TSound = class;  

   //eigentliche dekl.
TTest1 = class(TThread)
  private
    { Private}
   ...
  TSound = class
    private
      GoFlag:In
   ...

da gibts auch was in der Hilfe, wenn ich mich recht erinnere (Vorwärtsdeklaration, gugg mal da )


mimi - Di 07.10.03 22:14

diese art kenne ich garnicht, könntes du die genauer beschreiben ?
werde ich morgen mal testen


Keldorn - Mi 08.10.03 08:17

Hallo
hatte in meinem Post noch nen Fehler drin, habs korrigiert.
muß TTest1 = class; statt TTest1 = class(thread); heißen :oops: :oops:

Ist es denn so schwer den begriff in der Hilfe einzugeben? Besser erklären als da kann ich es sowieso nicht. in der D6pro Hilfe gehts direkt über den Index, bei D5Std muß man über die suche gehen. Den Topic Vorwärtsdeklarationen und voneinander abhängige Klassen gibts aber auch in der d5 Hilfe.

Mfg Frank


mimi - Mi 08.10.03 17:50

danke werde ich testen.


mimi - Mi 08.10.03 18:03

also in meiner delphi 6 Hilfe konnte ich leider nichts finden über diese art von klassen defination.

kann mir jemmand ein beispiel schreiben ?

Danke


Keldorn - Do 09.10.03 08:54

mimi hat folgendes geschrieben:

kann mir jemmand ein beispiel schreiben ?


was glaubst du was in meinem ersten Post steht? :roll:

Zitat:

also in meiner delphi 6 Hilfe konnte ich leider nichts finden über diese art von klassen defination.

Delphi-Hilfe -> Suchen -> Vorwärtsdeklaration eingeben

ein andere Variante wäre für 2 Units
(nur Beispielcode)
1. unit: (unit2)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
unit Unit2;

interface

uses classes, unit3;

type
  TTest1 = class(TThread)
  private
  protected
    Sound:TSound;
  public
  published
  end;

implementation

end.


2. unit (unit3):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
unit Unit3;

interface

uses classes;

type
  TSound = class(TObject)
  private
    Test:TObject;  // nur als tObject
    procedure Zugriff;
  protected
  public
  published
  end;

implementation

uses unit2;  //in implemention teil unit 

Procedure TSound.Zugriff;
Var myThread:TThread;
  begin
    myThread := TThread(Test); //zugriff
  end;

end.

was anderes würde mir nicht einfallen, würde aber die Typumwandlung vermeiden (hier schleichen sich für mich viel zu schnell Fehler ein und es wird zu uneindeutig (was ist test bei tsound...)) und alles in eine unit schreiben.

Mfg Frank


mimi - Do 09.10.03 15:56

habe es jetzt geschaft, aber ein problem habe ich nocht:
ich möchte variabeln von TSound nutzen aus TTest1 wie köntne ich das am besten machen ?


Anonymous - Do 09.10.03 15:59

wenn die sich gegenseitig verwenden, geht das nur mit pointern.
z.B:


Delphi-Quelltext
1:
PSound = ^TSound;                    


mimi - Do 09.10.03 17:15

könntes du mal ein ausfürhlichers beispiel geben ?
ich habe jetzt eine variable PSound erstellt(als Pointer) habe aber das problem das jetzt PSound = Nil ist.
ich wollte die variabeln dirckt nutzen, geht das auch irngendwie ?


mimi - Do 09.10.03 18:14

warum geht das nicht:
if @PSound.noTime = True then ShowMessage('TEST');
da sagt er immer:
Inkompatible Typen, warum ????


barfuesser - Do 09.10.03 18:17


Delphi-Quelltext
1:
if PSound^.noTime = true then ShowMessage('Test'); // falls noTime ein Boolean ist                    


[edit]
übrigens reicht bei Booleans auch die direkte Abfrage ohne den expliziten Vergleich mit true. Dieser liefert nämlich auch nur ein Bool, den man dann ja wieder mit true vergleichen müßte usw. usf.
[/edit]

barfuesser


mimi - Do 09.10.03 18:20

jetzt ist psound immer nil. muss ich ein pointer erst installiesiren ?


mimi - Do 09.10.03 18:27

ich habe es jetzt so versucht, aber das geht leider auch nicht :(

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
 TTest1 = class(TThread)
    public
    test:STring;
  end;

    TSound = class
    private
      GoFlag:Integer;
      test:TTest1;

    protected

    public
      PlayListe: array of TPlayListe;
      Random_Music: array of TPlayListe;
      laden,noTime:Boolean;
      AIndex:Integer;
      constructor create(pSoundFiles,SoundDir,DefaultExt:String;flag:Integer); // Lädt die Angebenden Sound Files
      procedure StopMusic; // stop alles geladene musik dateien.
      procedure NewMusik;
      procedure NewMusik2;
      procedure LoadMusikFile(Index:Integer;RM:Boolean);
      procedure AddPlayListe(FileName:String); // Fügt der Playliste eine Datei hinzu
      procedure PlayMusikFile(Index:Integer);
  end;

  TTest2 = class(TTest1)
    private

    protected
      procedure Execute; override;

    public
      PSound:TSound;
      Test:String;
      constructor Create(ACreateSuspended: Boolean);
  end;


Keldorn - Do 09.10.03 19:37

ich seh hier nicht mehr durch, was du tun willst.

du hat aber auch irgendwo im Thread bzw. TTest-constructor ein Sound:=TSound.create stehen?


mimi - Do 09.10.03 19:40

nein habe ich nicht.

ich möchte folgendes:
habe zwei klassen die sich gegenseitig brauchen.
nun wollte ich das mit pointern versuchen, aber das geht leider auch nicht :( :(


Keldorn - Do 09.10.03 19:48

mimi hat folgendes geschrieben:
nein habe ich nicht.



wenn du deine Objekte nicht erzeugst, was außer Nil soll denn dann der Inhalt sein?
oder wo erzeugst du dein Tsound objekt und weiß es Psound zu?


mimi - Fr 10.10.03 11:25

habe das problem gelöst, aber jetzt kommt eine endlos schleife, und ein res überlauf, ich glaube auch ich weiß warum *G*
den rest schaffe ich alleine, danke.

habe das jetzt mit diesen vorwärts dekaltion gemacht und fertig.


Motzi - Fr 10.10.03 11:33

Wieso brauchst du Pointer? Ein Objekt in Delphi ist bereits eine Referenz, also nichts anderes als ein Pointer auf den Bereich wo die Daten des Objektes liegen! Wieso brauchst du jetzt also einen Pointer auf einen Pointer? Ist das nicht etwas "doppltgemoppelt"?

Zu den Forwarddeklarationen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
type
  // Forward-Declaration
  TClass1 = class;
  TClass2 = class;

  // Class-Declaration
  TClass1 = class
    aClass2Object: TClass2;
  end;

  TClass2 = class
    aClass1Object: TClass1;
  end;

Eine Forwarddeklaration ist nichts anderes als ein abschließendes Semikolon (";") nach dem reservierten Wort "class", sonst nichts! Durch diese Forwarddeklaration weiß Delphi, dass es sich bei TClass1 und TClass2 um Klassen handelt und dass ihre eigentliche Klassendeklaration erst folgt. Aber dadurch, dass der Compiler bereits weiß dass es sich um Klassen handelt können diese im Interface bereits vor der eigentlichen Klassendeklaration verwendet werden.