Klasse in sich selbst aufrufen



  • Hiho,

    ich arbeite derzeit daran, Personen via Klasse als Freunde zusammenzufügen, um mich ein bisschen besser in die Materie einzuarbeiten.
    Dabei erstelle ich via

    Person hans("Hans Wurst");
     Person daniel("Daniel Käse");
    

    die Klasse für die Person Hans Wurst und die person Daniel Käse und füge via

    hans.befreunden(käse);
     daniel.befreunden(hans);
    

    die beiden als Freunde zusammen.

    Meine befreunden Funktion sieht derzeit so aus:

    void befreunden(Person p)              //Einlesen der Unterklasse "p" als Freund
        {
            freunde.push_back(p);
        }
    

    Dabei habe ich vorher freunde als Vektor in der Klasse definiert:

    vector<Person> freunde;
    

    Um das ganze logischer zu gestalten wollte ich nun aber, dass ich per einem einzigen Aufruf von befreunden die beiden Personen als Freunde zusammenfüge. In diesem Sinne dachte ich mir zunächst die Funktion in dieser Richtung umzuschreiben:

    void befreunden(Person *p)              //Einlesen der Unterklasse "p" als Freund
        {
            freunde.push_back(*p);
        }
    

    und dann mit

    hans.befreunden(&daniel);
    

    aufzurufen.
    Nun dachte ich mir in die Funktion befreunden

    p.freunde.push_back(   );
    

    hinzuzufügen. Leider habe ich aber keine Ahnung wie ich nun das Objekt Hans als Variable in dieser Funktion verwenden kann.

    Kann mir jemand helfen, sofern ihr verstanden habt was ich will? .



  • p->freunde.push_back(*this);
    

    Vielleicht wäre auch eine non-member Funktion hier sinvoller.



  • Ich habe mir für soetwas wie "gegenseitige Referenzierung" meist eine Hilfsklasse gebaut, welche das "Verheiraten" und "Scheiden" übernimmt. Der habe ich dann immer die beiden Objekte übergeben.


  • Mod

    Sinsei schrieb:

    Hiho,

    ich arbeite derzeit daran, Personen via Klasse als Freunde zusammenzufügen, um mich ein bisschen besser in die Materie einzuarbeiten.
    Dabei erstelle ich via

    Person hans("Hans Wurst");
     Person daniel("Daniel Käse");
    

    die Klasse für die Person Hans Wurst und die person Daniel Käse

    Du erstellst keine Klassen. Die Klasse ist Person. hans und daniel sind Instanzen (oder auch Objekte) der Klasse Person.

    und füge via

    hans.befreunden(käse);
     daniel.befreunden(hans);
    

    die beiden als Freunde zusammen.

    Du meinst wohl hans.befreunden(daniel);

    Meine befreunden Funktion sieht derzeit so aus:

    void befreunden(Person p)              //Einlesen der Unterklasse "p" als Freund
        {
            freunde.push_back(p);
        }
    

    Dabei habe ich vorher freunde als Vektor in der Klasse definiert:

    vector<Person> freunde;
    

    Das ist sehr ungewöhnlich, denn hiermit legst du Kopien der Freunde an, keine Verweise auf die Freunde.

    Um das ganze logischer zu gestalten wollte ich nun aber, dass ich per einem einzigen Aufruf von befreunden die beiden Personen als Freunde zusammenfüge. In diesem Sinne dachte ich mir zunächst die Funktion in dieser Richtung umzuschreiben:

    void befreunden(Person *p)              //Einlesen der Unterklasse "p" als Freund
        {
            freunde.push_back(*p);
        }
    

    und dann mit

    hans.befreunden(&daniel);
    

    aufzurufen.

    Du hast eine merkwürdige Vorstellung davon, was Logik einer Freundschaft angeht. Ich kann dich also zu meinem Freund erklären?

    Aber gut, nehmen wir bloß einmal an, dass das Beispiel ungünstig gewählt ist und es eine sinnvolle Anwendung gibt:

    #include <vector>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    class Person
    {
      string name;
      vector<Person*> freunde;
    public:
      Person(string name): name(name) {}
      void befreunden(Person& freund)
      {
        freunde.push_back(&freund);
        freund.freunde.push_back(this);
      }
      friend ostream& operator<<(ostream &out, const Person& person)
      {
        out << "Ich bin " << person.name << " und meine Freunde sind:";
        for(auto freund: person.freunde)
          out << '\n' << freund->name;
        return out;
      }
    };
    
    int main()
    {
      Person hans("Hans Dampf");
      Person daniel("Daniel Käse");
    
      hans.befreunden(daniel);
      cout << hans << '\n' << daniel << '\n';
    }
    

    Und wehe dir, die Freunde sind tot, wenn sie ausgegeben werden! Daher wäre es vielleicht sinnvoll, das Design etwas zu überdenken.



  • void befreunden( Person* p )
    {
        freunde.push_back( *p );
        p.freunde.push_back( this );
    }
    

    Ich würde an deiner Stelle die Freunde nicht per Kopie verwalten.



  • Aufbauend auf dem, was SeppJ schrieb:

    (Edit: Und nochmal angepasst)

    #include <iostream>
    #include <vector>
    #include <list>
    #include <string>
    #include <utility>
    #include <memory>
    
    struct Person
    {
      std::string name;
      std::vector<Person*> freunde;
    };
    
    struct Welt
    {
      std::vector<std::unique_ptr<Person>> bewohner;
    
      Person* neuer_bewohner(std::string name);
    };
    
    Person* Welt::neuer_bewohner(std::string name)
    {
      std::unique_ptr<Person> p (new Person);
      p->name = move(name);
      bewohner.push_back(move(p));
      return bewohner.back().get();
    }
    
    void befreunde(Person* wen, Person* mit)
    {
      // TODO: ueberlegen, ob und wie man abfangen soll,
      // falls die zwei personen schon befreundet sind
      // oder ob wen==mit gilt.
      wen->freunde.push_back(mit);
      mit->freunde.push_back(wen);
    }
    
    int main()
    {
      Welt w;
      Person* hans   = w.neuer_bewohner("Hans Wurst");
      Person* daniel = w.neuer_bewohner("Daniel Kaese");
      befreunde(hans,daniel);
    }
    

    (kompiliert)

    Es ist sicherlich sinnvoll, durch Einsatz von privaten Elementen (private:) dafür zu sorgen, dass gewisse Invarianten nie verletzt werden. Beispielsweise kann man sich auf doppelseitige Freundschaften beschränken. Und falls ein Bewohner gelöscht werden soll, darf man natürlich nicht vergessen, die Freundeslisten von anderen dementsprechend anzupassen.

    Cheers!
    k.k.



  • Warum erwähnst du boost::noncopyable und verwendest dann ein hässliches Makro? 👎
    Und warum Zeiger statt Referenzen?



  • Ich hatte erst boost::noncopyable verwendet, musste aber dann feststellen, dass ideone den entsprechenden Header nicht griffbereit hat. So wird's von ideone im C++0x Modus kompiliert.

    Wie Du das Makro findest, interessiert mich nicht wirklich.

    Edit: Mit vector<unique_ptr<Person>> statt list<Person> finde ich es doch besser. Dann muss ich auch nicht explizit sagen, dass Welt unkopierbar ist.



  • Danke erstmal.

    Via

    void befreunden(Person *p)              //Einlesen der Unterklasse "p" als Freund
        {
            freunde.push_back(*p);
            p->freunde.push_back(*this);
        }
    

    funktioniert das Ganze jetzt auch, nur habe ich nun noch ein anderes Problem.

    SeppJ schrieb:

    Du erstellst keine Klassen. Die Klasse ist Person. hans und daniel sind Instanzen (oder auch Objekte) der Klasse Person.

    Danke, wusste nicht, dass man das Objekt nennt.

    SeppJ schrieb:

    Du meinst wohl hans.befreunden(daniel);

    Jup, meinte ich, leider nicht ganz richtig über den Beispiel-Code nachgedacht.

    SeppJ schrieb:

    Das ist sehr ungewöhnlich, denn hiermit legst du Kopien der Freunde an, keine Verweise auf die Freunde.

    Und hier denke ich liegt jetzt wohl auch mein neues Problem. Vielleicht um euch mal mehr Einblick zu gewähren:

    Ich habe eine main-funktion als Übung, die nicht verändert werden darf. Diese sieht so aus:

    int main()
    {
    	Person daniel("Daniel Düsentrieb");
    	Anschrift anschrift;
    	anschrift.strasse = "Raketenweg";
    	anschrift.hausnummer = "12";
    	anschrift.postleitzahl = 90560;
    	anschrift.stadt = "Entenhausen";
    	daniel.setzeAnschrift(anschrift);
    	cout << "daniel.text(): " << daniel.text() << endl;
    
    	Person donald("Donald Duck");
    	anschrift.strasse = "Entengasse";
    	anschrift.hausnummer = "3";
    	anschrift.postleitzahl = 90560;
    	anschrift.stadt = "Entenhausen";
    	donald.setzeAnschrift(anschrift);
    
    	cout << "\nDaniel und Donald werden Freunde:\n";
    	daniel.befreunden(&donald);
    	cout << "daniel.text(): " << daniel.text() << endl;
    	cout << "donald.text(): " << donald.text() << endl;
    
    	Person person;
    	cout << "\nEine geheimnisvolle Person befreundet sich mit allen anderen:\n";
    	person.befreunden(&daniel);
    	person.befreunden(&donald);
    	cout << "person.text(): " << person.text() << endl;
    
    	anschrift.strasse = "Erpelhofer Str.";
    	anschrift.hausnummer = "12";
    	anschrift.postleitzahl = 90560;
    	anschrift.stadt = "Entenhausen";
    	cout << "\nDonald zieht um nach " << anschrift.text() << endl;
    	donald.setzeAnschrift(anschrift);
    	cout << "daniel.text(): " << daniel.text() << endl;
    }
    

    Um dieses Konstrukt herum soll ich nun meine Klassen so aufbauen, dass ein bestimmter Text entsteht.

    Mein Problem ist jetzt, wie ihr schon vermutet habt, dass ich nur Kopien in dem Vektor drinstehen habe und somit via

    donald.setzeAnschrift(anschrift);
    

    gegen Ende hin zwar die Anschrift der Person verändere, aber nicht die Anschrift dieser Person bei den Freunden. Mir wird also bei

    cout << "daniel.text(): " << daniel.text() << endl;
    

    immer noch die alte Adresse von Donald Duck ausgegeben als Freund und nicht die Neue.

    Die wohl wichtigen Funktionen in meinen Klassen hierfür wären nun:

    Anschrift adresse;
    
        vector<Person> freunde;
        void befreunden(Person *p)              //Einlesen der Unterklasse "p" als Freund
        {
            freunde.push_back(*p);
            p->freunde.push_back(*this);
        }
    void Person::setzeAnschrift(Anschrift a)
    {
        adresse = a;
    }
    

    Leider weiß ich nun jetzt nicht genau, was oder wie ich etwas ändern müsste, damit in dem Vektor eben nur die Adresse drin steht und nicht eine Kopie.

    Besonders an SeppJ: Tut mir Leid, falls ich irgendwie dumm oder sonst wie rüberkomme, aber ich möchte nur in C++ besser werden und frage deswegen hier nach.

    mfg Sinsei 🙂



  • Sinsei schrieb:

    Ich habe eine main-funktion als Übung, die nicht verändert werden darf.

    ... hättest Du ruhig mal eher erwähnen können.

    Sinsei schrieb:

    Leider weiß ich nun jetzt nicht genau, was oder wie ich etwas ändern müsste, damit in dem Vektor eben nur die Adresse drin steht und nicht eine Kopie.

    Du weißt nicht, was Du ändern musst? Guck Dir doch nochmal den kompletten Thread hier an. Fällt Dir da nix auf? Gar nix?


Anmelden zum Antworten