Objekte dynamisch erzeugen, in (z. B.) Vector schreiben, auf die Objekte zugreifen



  • Weil auf Vector-Elemente direkt nur über ihre Position zugegriffen werden kann.

    Na und?

    Was unterscheidet denn Männer und Frauen in deinem Modell derart, dass du dafür zwei verschiedene Klassen brauchst?



  • Hallo Cordula,

    mmmh... so nebenher, bei dem was Du vorhast, würde ich von Maps (so wie Du sie verwendest) echt abraten. Bei einer std::map<K,T> muss jeder Key eindeutig sein. Das würde bedeuten, dass Du nur z.B. eine einzige Person mit z.B. braunen Haaren oder zehn Fingern ansprechen kannst.

    Gruß
    PuerNoctis



  • @PuerNoctis: Die Elemente sind in der Tat genau einmal vorhanden, bzw. der Schlüssel nach dem ich nach den Objekten suchen würde, hier die Fingeranzahl, ist eindeutig. Gut, die Fingeranzahl als Beispiel zu nehmen war vielleicht unglücklich. Ist das der einzige Grund das Map nicht zu benutzen?

    @Michael E.: Und wenn ich die Objekte nicht in einem anderen Container halte, wo ich sie über den Key erreichen kann, nützt mir die Position im Vector wenig. Außer man nimmt das find_if, aber ich weiß nicht ob das nicht etwas übertrieben ist für die konkrete Anwendung.
    Hier braucht man keine gesonderten Klassen, mein Program soll biochemische Zusammenhänge verarbeiten und ich wollte nicht den konkreten Code als Beispiel nennen, da er 4mal mehr Erklärungen bedarf als die Menschen mit den Fingern bedarf.



  • Wenn es tatsächlich um Männer und Frauen geht, spar dir die Vererberei und speicher Mann oder Frau in der Klasse Mensch. Es wird (vermutlich) nie etwas anderes geben als Männer und Frauen, du brauchst hier also keine erweiterbare Lösung. Das eventuell extrem unterschiedliche Verhalten von Mann und Frau kannst Du z.B. mit dem Strategie Muster modellieren. Da kann man dann auch später noch das Verhalten einer zickigen Frau dazudichten.

    Deine Sucherei:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    
    class Mensch
    {
    public:
        enum Gender {Frau, Mann};
    
        Mensch(const std::string& name, Gender g, unsigned groesse) :
            geschlecht_(g), groesse_(groesse), finger_(10), name_(name)
        {}
    
        Gender Geschlecht() const{ return geschlecht_; }
        unsigned Finger() const { return finger_; }
        const std::string& Name() const { return name_; }
    
        void HackFingerAb(unsigned finger)
        {
            finger_ -= std::min(finger_, finger);
        }
    
    private:
        Gender geschlecht_ ;
        unsigned groesse_, finger_;
        std::string name_;
    };
    
    bool FrauMit7Fingern(const Mensch& m)
    {
        return m.Geschlecht() == Mensch::Frau && m.Finger() == 7;
    }
    
    int main ()
    {
        std::vector<Mensch> menschen;
        menschen.push_back(Mensch("Uschi", Mensch::Frau, 175));
        menschen.push_back(Mensch("Uwe", Mensch::Mann, 125));
        menschen.push_back(Mensch("Chantalle", Mensch::Mann, 185));
    
        menschen[0].HackFingerAb(3); // Hack Uschi 3 Finger ab!
    
        std::vector<Mensch>::const_iterator it = 
            std::find_if(menschen.begin(), menschen.end(), FrauMit7Fingern);
    
        std::cout << it->Name(); // Uschi
        return 0;
    }
    


  • Cordula schrieb:

    @Michael E.: Und wenn ich die Objekte nicht in einem anderen Container halte, wo ich sie über den Key erreichen kann, nützt mir die Position im Vector wenig. Außer man nimmt das find_if, aber ich weiß nicht ob das nicht etwas übertrieben ist für die konkrete Anwendung.

    Es tut mir Leid, aber ich verstehe dein Problem nicht.



  • @brotbernd: Wow! Vielen Dank für die Mühe die du dir gemacht hast 🙂 Ich werde schon Klassen nehmen, werde also dein Code anpassen 🙂

    Nur so zur Info - ist das mit dem map sehr schlecht, abgesehen davon dass es viel uneffektiver ist als find_if? Ich will was lernen 🙂 Danke nochmal.



  • find_if ist eine simple Schleife die alle Elemente im vector anguckt, bis was passendes gefunden ist. Es kommt drauf an, was du mit effizient meinst. Das Suchen geht in der map viel schneller. Dafür dauert das Einfügen länger und mehr Speicher wird benötigt. Wenn Du eine Datei einliest und danach keine Elemente mehr hinzukommen, wäre ein sortierter Vector wohl am effizientesten.
    Wenn du von Programmierfiizienz redest, ist die einfachste Lösung die beste und das ist wohl vector + find_if.



  • brotbernd schrieb:

    menschen.push_back(Mensch("Chantalle", Mensch::Mann, 185));
    

    Das sind doch die, die in Nachtbars als "Bardamen" arbeiten, oder?

    Edit: Sorry, offtopic



  • Danke für die ausführliche Erklärung 🙂

    Den Code hab ich auch schon _fast_ angepasst 🙄

    Einen Fehler werd ich nicht los ..

    invalid use of non-static member function 'bool Read::Fraumit7Fingern(const Mensch&)'

    Jemand ne Idee?



  • Du rufst die Funktion ohne Instanz auf:

    Mensch foo;
    
    // du machst:
    Read::Fraumit7Fingern(foo);
    
    // richtig wäre, da es sich nicht um eine statische Funktion handelt:
    Read reader;
    reader.Fraumit7Fingern(foo);
    

    Das ist aber nur ne Vermutung, weil du keinen Quelltext zeigst.



  • Danke, das hat gestimmt.

    Aber danach bekomm ich trotzdem andere Fehler zurück. Hier der Code:

    vector<Mensch> MenschVec;
    vector<Mensch>::iterator itMe;
    
    MenschVec.push_back(Mensch(attr1, attr2, attr3));
    MenschVec.push_back(Mensch(attr4, attr5, attr6));
    MenschVec.push_back(Mensch(attr7, attr8, attr9));
    
    std::vector<Mensch>::const_iterator itMe = std::find_if(MenschVec.begin(), MenschVec.end(), FrauMit7Fingern);
    cout << itMe -> Haare << endl;
    

    Also soll die Frau mit den 7 Fingern gefunden werden und ihre Haarfarbe zurückgegeben werden.
    Nach der Korrektur heißt es:

    'itMe' has previous declaration as '__gnu_cxx::__normal_iterator<Mensch*,std::vector<Mensch,std::allocator<Mensch>>>'
    No matching function for call to 'Read::Fraumit7Fingern'
    Conflicting declaration '__gnu_cxx::__normal_iterator<const Mensch*std::vector<MEnsch,std::allocator<Mensch>>>itMe'



  • Zum 1. und 3. Fehler: du hast itMe 2mal deklariert. Lösch einfach vector<Mensch>::iterator itMe;

    zum 2. Fehler: Dein Compiler findet Read::Fraumit7Fingern' nicht.
    Dazu kann man wegen fehlenden Code nichts sagen.



  • Ich möchte nicht übertreiben - aber ich bin grad schon übermüdet, also eine letzte Frage:

    Was heißt

    argument of type 'bool (Read:: )(const Mensch&)' does not match 'bool (Read::*)(const Mensch&)'

    Ich hab eine Erklärung über calling a member function using a pointer-to-member function gefunden, aber ehrlich gesagt hab ich sie nicht wirklich verstanden. Und da ich damit keine Erfahrung habe ist es noch schwieriger 🙄

    Danke für eure Antworten.



  • Scheinbar rufst du FrauMit7Fingern nicht korrekt auf.
    Warum muß diese Funktion denn eine Memberfunktion sein?

    Ich bevorzuge an der Stelle eigentlich Funktoren. Also etwa so:

    struct FrauMitAnzahlFingern {
     private:
      int m_anzahl;
     public:
      FrauMitAnzahlFingern(int anzahl) : m_anzahl(anzahl) {}
      bool operator()(const Mensch& mensch) {
        return mensch.Geschlecht() == Mensch::Frau && mensch.Finger() == m_anzahl;
      }
    };
    
    // Aufruf dann so
    std::vector<Mensch>::const_iterator itMe = std::find_if(MenschVec.begin(), MenschVec.end(), FrauMitAnzahlFingern(7));
    

    Da kann man dann auch gleich nach anderen Anzahlen suchen. Außerdem hat es der Compiler etwas leichter mit dem Optimieren.



  • Läuft 🙂

    Find ich auch übersichtlicher mit dem Funktor 🙂

    Danke vielmals, und noch nen schönen Abend.
    C.


Anmelden zum Antworten