Header include Kreisschluss.
-
Der Trick ist, dass du die vollständige Definition der einen Klasse nur in den Funktionsdefinitionen, also im Source der jeweils anderen brauchst. Sprich: Im Header von A brauchst du nur die Deklaration, den Namen von B, aber nicht dessen vollständige Definition. Die ist in B.h. Und in B.h braucht die Klassendefinition von B nur den Namen von A, nicht aber A's Definition.
In den Source-Dateien beider Klassen bindest du dann ganz entspannt beide Header ein, (B.h und A.h).
Und um von einer Klasse nur den Namen bekannt zumachen, machst du eine Vorwärtsdeklaration:class B; // bzw. class A;
-
cl90 schrieb:
Wenn ich eine Struktur machen möchte in der zwei Klassen gegenseitig funktionen von sich ausführen können bekomme ich ja Probleme mit den header Kreisincludes.
Nicht notwendigerweise, nein.
cl90 schrieb:
Also weil Klasse A, den Header von Klasse B includen muss um ein Objekt von B erstellen zu können, und Klasse B den header von Klasse A includen muss damit es public/protected erben kann.
Wie meinst Du das genau? Zeig doch mal.
cl90 schrieb:
Eine Möglichkeit das zu umgehen ist z.B. ein Observer. Aber irgendwie finde ich das ziemlich nervig. Gibt es denn keine bessere Lösung?!
Wahrscheinlich, ja.
-
ok aber dann gehen z.b. die autocomplete funktionen nicht mehr. Wär nicht ganz so tragisch aber vlt gehts noch besser.
Also das hier ist ein simples Beispiel von dem was ich machen möchte.
Die Klasse Bla hat ein Objekt von DelayHandle und führt Funktionen von DelayHandle aus.
In dem Fall das ein aktiver Thread von Bla aus Funktionen von DelayHandle ausführt, kann ich durch return oder call bei Ref, alles an Informationen aus aufgerufenen Funktionen bekommen die ich brauche.
Wenn ich im DelayHandle aber einen Thread starte, der dann nach Zeit/WhatEverEvent Bla bescheid gibt, komme ich an diese Stelle.
- Entweder ich ändere eine Variable die von Bla regelmäßig geprüft wird,
- ich sende ein Notify über einen Observer,
- oder ich bringe DelayHandle bei direkt auf die Funktionen von Bla zuzugreifen. So wie im folgendem Code angedeutet:
Aber das ist wie gesagt die frage... Wie baut man das ohne beide Klassen im selben header zu haben...// header 1 #include "bla.h" class DelayHandle : public bla { public: DelayHandle(); ~DelayHandle(){}; _ErrType tryDelayedUpdate() { //starte thread.. etc // mach dies.. // und das... recall(); } }; //header 2 #include "DelayHandle.h" // kreisschluss class bla { public: bla(); ~bla(){}; void recall(); void request() { m_delayHandle.tryDelayedUpdate(); }; private DelayHandle m_delayHandle; };
-
Das kann nicht funktionieren.
bla hat einen DelayHandle-Member -> Jedes bla enthält ein DelayHandle.
DelayHandle ist von bla abgeleitet -> Jedes DelayHandle enthält ein bla.
Wo soll das enden?Falls das nur ein Vereinfachungsfehler war (es ist nicht dasselbe bla), hilft es dir vermutlich schon, die Methoden nicht im Header zu definieren.
-
ja genau, das meine ich ja. Deshalb nehme ich da bisher immer Observer.
Es kam nur die Frage auf, ob es auch anders geht.
-
Nur nochmal zur Klarstellung: Du hast kein Problem mit Header-Include-Kreisen, du hast ein Problem mit deinem Klassendesign, das zwangsweise zu Header-Include-Kreisen führt.
cl90 schrieb:
Es kam nur die Frage auf, ob es auch anders geht.
Na sicher. Entweder erbt DelayHandle nicht von bla, oder bla enthält kein DelayHandle als Value-Member. Was davon sinnvoll ist, kann man nicht sagen, ohne die Klassen genauer zu kennen.
-
Wie genau meinst du das?
Es geht darum, dass sowohl: (Obj a, b)
a -> Funktionen von b ausführen kann, als auch
b -> Funktionen von a ausführen kann.Wäre das dann noch gewährleistet?
-
Ich blick hier schon von Anfang an nicht durch. Wieso müssen die überhaupt von einander erben?
Und wieso erzeugt der parent Objekte vom Child?
-
cl90 schrieb:
Wäre das dann noch gewährleistet?
Ist dir klar, dass das bla-Objekt, dessen recall-Methode du in DelayHandle::tryDelayedUpdate aufrufst, nicht dasselbe ist, das in seiner request-Methode tryDelayedUpdate aufgerufen hat?
Es geht nicht darum, dass du ein Objekt des passenden Typs zum Aufrufen hast. Du musst das richtige Objekt haben.
Warum gibst du tryDelayedUpdate nicht einfach eine Referenz auf das aufrufende bla mit? Dann nimmst du die sinnlose Vererbung raus, und schon reicht dir in DelayHandle.h eine Forward Declaration von bla.
-
[quote="MFK]Warum gibst du tryDelayedUpdate nicht einfach eine Referenz auf das aufrufende bla mit? Dann nimmst du die sinnlose Vererbung raus, und schon reicht dir in DelayHandle.h eine Forward Declaration von bla.[/quote]
Dann sind wir immer noch beim Header Kreisschluss...Bla hat ein Objekt DelayHandle, braucht also den Header von DelayHandle.
DelayHandle bekommt eine Referenz von Bla. Braucht also den Header von Bla um Bla zu kennen. -> Kreisschluss.
Dafür war jetzt hier die Lösung aufgekommen das Objekt Bla oder DelayHandle in Form von einem Namen bekannt zu machen, aber nicht den header zu laden.Es hat mich nur interessiert ob es noch weitere Möglichkeiten gibt, zusätlich zu der die ich kenne.
Und wozu diese Vernetzung wichtig ist:
Es gibt keine andere Sinvolle Lösung wenn ein eben erstellter Thread einer Klasse einer anderen Klasse bescheidgeben will.Bla -> meldet sich als Observer bei DelayKlasse an.
Bla -> Request an Delay Klasse
Delay Klasse -> Starte Thread mit Zeitpunkt.
Bla macht inzwischen irgendetwas anderes
Thread -> notify über den Observer an Bla.
Thread führt im Notify aufgelistete Funktion sofort aus ohne das Bla ein gesetztes Flag irgendwo abfragt und dann erst reagiert.Man könnt den Thread natürlich in der Klasse des Zielaufrufes erstellen, aber das dann kann ich auch gleich auf OOP und Ordnung verzichten.
-
cl90 schrieb:
DelayHandle bekommt eine Referenz von Bla. Braucht also den Header von Bla um Bla zu kennen. -> Kreisschluss.
Nein. Für einen Referenz-Parameter in einer Methodendeklaration reicht eine Forward Declaration. Die Definition der Methode braucht natürlich den Header, aber das kannst du in DelayHandle.cpp machen.
cl90 schrieb:
Man könnt den Thread natürlich in der Klasse des Zielaufrufes erstellen, aber das dann kann ich auch gleich auf OOP und Ordnung verzichten.
Ganz ehrlich: Ich glaube nicht, dass du OOP verstanden hast. Du kennst anscheinend den Unterschied zwischen Instanz und Klasse nicht, und hast meiner Meinung nach immer noch nicht verstanden, warum deine "Lösung" nicht funktioniert.
-
Es war nie meine Lösung.
Es war eine Frage ob man etwa in dieser, bzw ähnlicher Form bauen kann um einen Observer überflüssig zu machen.Und das wurde hier jetzt wohl schon mehrfach beantwortet.