header Dateien, Klassen beziehen sich aufeinander



  • Hallo zusammen,

    ich bin neu hier und bin ein Anfänger in Sachen C++ und bitte um Nachsicht.
    Ich hab ein kleines Programm geschrieben mit zwei Klassen.
    Solange die Klassen unabhängig voneinander sind, funktioniert alles.
    Versuche ich in einer Klasse (Tierheim) ein Attribut mit dem Typ der anderen Klasse (Hund) zu erstellen, gibt es Probleme. Kann mir jemand sagen, wie man es richtig macht? (Komischerweise funktioniert es, wenn ich den kompletten Code in eine Datei (main.cpp) schreibe.)
    Hier mein Programm:

    //Hund.h
    class Hund{
    private:
    int i;
    public:
    void set_i();
    void get_i();};

    //Hund.cpp
    #include "Hund.h"
    void Hund::set_i() {}
    void Hund::get_i() {}

    //Tierheim.h
    class Tierheim{
    private:
    int i;
    public:
    Hund hund; //warum funktioniert das so nicht?
    void set_i();
    void get_i();};

    //Tierheim.cpp
    #include "Tierheim.h"
    void Tierheim::set_i(){}
    void Tierheim::get_i(){}

    //main.cpp
    #include <iostream>
    #include "Tierheim.h"
    #include "Hund.h"
    int main(){
    Hund hund1;
    Tierheim Tierheim1;}

    Vielen Dank im Voraus!



  • Ein Hund ist dem Tierheim unbekannt. Soll heißen, Tierheim.h müsste Hund.h inkludieren (eine Vorwärtsdeklaration würde auch nicht reichen). Allerdings passt das logisch nicht, da ein Tierheim nicht immer nur genau einen Hund in Pflege hat.
    Für die i passen auch jeweils die Getter und Setter nicht. Was soll das i in dem Kontext bedeuten?



  • gibt es Probleme

    ist keine Fehlerbeschreibung.

    Wie/womit lernst du? In deinen Headern fehlen die Include Guards. Wenn du eine Klasse benutzen willst, musst du den entsprechenden Header per include einbinden. Das sollte dein Lernmaterial erklären.



  • @manni66

    Hallo zusammen,

    wie man leicht sieht, geht es mir momentan nicht um ein inhaltlich sinnvolles Programm, sondern um die Verknüpfung von Klassen und Objekten in C++ usw.
    Ich lerne mit Visual Studio 2017 (leeres Projekt) und benutze meine Vorlesungsunterlagen, Google usw.
    Das obere Programm habe ich ein wenig überarbeitet und komme jetzt wieder nicht weiter: Ich kann in der Klasse Tierheim Variablen vom Typ Hund bilden.
    Nun wollte ich auch, dass ein Hund eine Variable vom Typ Tierheim hat. (Z.B. bekommt ein einquartierter Hund eine Hundemarke mit dem Namen des Tierheims verpasst). Dazu habe ich in der Hund.h einfach Tierheim.h mit include hinzugefügt.
    Aber das das funktioniert anscheinen nicht. Es kommt ein ganzes Arsenal an allen möglichen Fehlern. Hier das überarbeitete Programm:

    //Hund.h
    #ifndef HUND_H
    #define HUND_H

    #include <string>
    // #include "Tierheim.h" warum funktioniert das nicht???

    class Hund
    {
    private:
    std::string hundename;
    static int hunde_objekt_zaehler;
    public:
    void setName(std::string value);
    std::string getName();
    int get_Hunde_Objekt_zaehler();
    };

    #endif //

    //Hund.cpp
    #include "Hund.h"

    void Hund::setName(std::string value) {
    hundename = value;
    }

    std::string Hund::getName() {
    return hundename;
    }

    int Hund::get_Hunde_Objekt_zaehler() {
    return hunde_objekt_zaehler;
    }

    //Tierheim.cpp
    #include "Tierheim.h"

    void Tierheim::setName(std::string value) {
    TH_name = value;
    }

    std::string Tierheim::getName() {
    return TH_name;
    }

    void Tierheim::setHund(Hund *value){
    zaehler_Hunde_im_Tierheim++;
    Hunde[zaehler_Hunde_im_Tierheim] = value;}

    int Tierheim::getZaehler_Hunde_im_TH() {
    return zaehler_Hunde_im_Tierheim;}



  • @Nichtskoenner
    sorry, irgendwas ist gerade schiefgegangen. Hier der restliche Code:

    //Tierheim.h
    #ifndef TIERHEIM_H
    #define TIERHEIM_H

    #include <string>
    #include "Hund.h"

    class Tierheim {
    private:
    std::string TH_name;
    Hund *Hunde[100];
    int zaehler_Hunde_im_Tierheim = 0;

    public:
    void setName(std::string value);
    std::string getName();

    void setHund(Hund *value);
    
    int getZaehler_Hunde_im_TH();
    

    };
    #endif //

    #include <iostream>

    //main.cpp

    #include "Hund.h"
    #include "Tierheim.h"

    int Hund::hunde_objekt_zaehler = 0;

    int main()
    {
    Hund *Hunde[100];
    Hunde[1] = new Hund;
    Hunde[1]->setName("Bello");

    Hunde[2] = new Hund;
    Hunde[2]->setName("Rex");
    
    Tierheim dasTierheim;
    dasTierheim.setHund(Hunde[1]);
    dasTierheim.setHund(Hunde[2]);
    

    }

    Und noch eine Frage: Wie kann ich den Quellcode hier vernünftig anzeigen lassen?
    Irgendwie klappt das nicht 😞

    Vielen Dank im Voraus!



  • Mein Frage ist, ob das überhaupt möglich ist, dass eine Klasse sich auf ein zweite Klasse bezieht und diese sich wieder auf die erste. Und wenn ja, wie kann man das realisieren. Irgendwie kommt es mir wie ein "Henne-Ei-Problem" vor.

    Nochmal vielen Dank im Voraus!



  • @Nichtskoenner sagte in header Dateien, Klassen beziehen sich aufeinander:

    Mein Frage ist, ob das überhaupt möglich ist, dass eine Klasse sich auf ein zweite Klasse bezieht und diese sich wieder auf die erste.

    Ja

    Und wenn ja, wie kann man das realisieren. Irgendwie kommt es mir wie ein "Henne-Ei-Problem" vor.

    Mit Pointern.

    Wie schon gesagt: das sollte dein Lernmaterial erklären.



  • @Nichtskoenner sagte in header Dateien, Klassen beziehen sich aufeinander:

    Mein Frage ist, ob das überhaupt möglich ist, dass eine Klasse sich auf ein zweite Klasse bezieht und diese sich wieder auf die erste.

    Nicht ohne weiteres. Denn damit ich in einer Klasse eine Membervariable einer anderen Klasse haben kann, muss der Compiler diese (insbesondere deren Speicherbedarf) kennen. Das funktioniert aber nicht, wenn man sich gegenseitig includet. Bei zyklischen Beziehungen muss daher irgendenwo eine Bruch stattfinden. Diesen durchbricht man mit Pointern oder Referenzen auf die andere Klasse. Dazu reicht dann eine Vorwärts-Deklaration aus (forward declaration). Schau dir mal in deinen Unterlagen an, wie das geht.

    Aber was anderes: es ist zumindest sehr fragwürdig, ob ein Hund ein Tierheim als Member haben sollte... Ein Verweis auf ein Tierheim, in dem der Hund lebt, erscheint deutlich sinnvoller. Und damit gibt es dann auch kein Problem.



  • @wob

    Danke dir für die Stichworte "zyklische Beziehungen" und "Vorwärtsdeklaration" werde danach mal suchen. (Stehen leider nicht in meinen Lernunterlagen.)

    "Verweis auf ein Tierheim, in dem der Hund lebt, erscheint deutlich sinnvoller..."
    Mit "Verweis" meinst du jetzt einfach eine Variable z.B. Name_Tierheim vom Typ string in der Klasse Hund?

    class Hund
    {
    private:
    std::string hundename;
    static int hunde_objekt_zaehler;
    std::string name_TH;
    public:
    void setName(std::string value);
    std::string getName();
    int get_Hunde_Objekt_zaehler();
    void setName_TH(std::string value);
    };



  • Mit Verweis meint er C++ Sprachelement: Referenz.

    Hier mal eine minimalisiertes Beispiel mit einem Zeiger,
    wie man eine zyklische Abhängigkeit löst.

    • Tierheim HPP bleibt im Prinzip unverändert.

    • Tierheim Forward HPP

      class Tierheim;
      
    • Hund.hpp

      #include "tierheim_forward.hpp"
      
      class Hund
      {
      public:
          Hund(Tierheim* meinTierheim);
      
      private:
          Tierheim* meinTierheim_; // nicht besitzend, also kein   Speichermanagement machen.
      };
      
    • Hund CPP

      #include "tierheim.hpp" // hier die definition includen.
      // ab jetzt kannst du den Zeiger auch dereferenzieren / benutzen, da die   Definition nun da ist.
      
      Hund::Hund(Tierheim* meinTierheim)
          : tierheim_{meinTierheim}
      {
      }
      


  • Und hier nochmal eins mit Referenzen.
    Auch wenn hier das Problem keine zyklischen Abhängigkeiten sind,
    aber es benutzt das gleiche Prinzip.

    • Mein Header

      #include <iosfwd> // forward deklarationen für iostreams
      //#include mysomething
      
      // hier braucht es noch keine Definition der Klasse "ostream".
      // Erst wenn man die Referenz "benutzt".
      void blubber(std::ostream& stream, MySomething const& bla);
      
    • Meine Sourcefile

      #include <iostream>
      
      void blubber(std::ostream& stream, MySomething const& bla)
      {
          stream << bla.name() << ": " << bla.counter();
      }
      
    • Main

      //#include mysomething
      //#include mein header
      #include <fstream>
      
      int main()
      {
          MySomething cat;
          std::ofstream writer{"test.txt", std::ios_base::binary};
          blubber(writer, cat);
      }
      

Anmelden zum Antworten