geht das irgendwie einfacher



  • Hallo,

    Ich habe folgende Klasse:

    class CLied {
      bool   m_found;
      string m_type;
      string m_titel;
      string m_interpret;
      string m_info;
    
      public:
        CLied () {
          m_type = "";
          m_titel = "";
          m_interpret = "";
          m_info = "";
          m_found = TRUE;
        }
    
        CLied (string type, string titel, string interpret, string info) {
          m_type = type;
          m_titel = titel;
          m_interpret = interpret;
          m_info = info;
          m_found = TRUE;
        }
    
        bool getFound () {
          return (m_found);
        }
    
        string getTitel() {
          return (m_titel);
        }
    
        string getType() {
          return (m_type);
        }
    
        string getInterpret() {
          return (m_interpret);
        }
    
        string getInfo() {
          return (m_info);
        }
    
    // ...................usw...................
    
    };
    

    Kann ich das irgendwie einfacher machen. ich mein dass ich nicht immer getTitel, getType,... brauche sondern eine für alle mache die dann je nach aufruf das entsprechende macht??

    LG



  • Nun - die Vereinfachung liegt nicht darin, aus vielen get*-Methoden eine zu machen, die 'alles' liefert, sondern die Vereinfachung besteht darin, auf die get-Methoden ganz zu verzichten.
    Gretchenfrage: wozu brauchst Du die get-Methoden?

    Gruß
    Werner



  • BTW: benutze Initialisierungslisten und übergebe die string's per const Referenz - also:

    CLied () 
            : m_found( true ) // oder false?
            , m_type()
            , m_titel()
            , m_interpret()
            , m_info()
        {}
    
        CLied( const std::string& type, const std::string& titel, const std::string& interpret, const std::string& info) 
            : m_found( true )
            , m_type( type )
            , m_titel( titel )
            , m_interpret( interpret )
            , m_info( info )
        {}
    

    .. und schreibe nie using namespace std; in eine H-Datei.

    Gruß
    Werner



  • Werner ... Getter sind schon ok ... eigentlich sogar gut.

    kannst es dir verkleinern oder wie du es nenen willst ^^ in dem du einfach nen stringarray nimmst und den dem getter einfach die id des zu nutzenden strings gibst ...



  • Wenn "CLied" eine "dumme Datenklasse" ist sind Getter IMHO für nix. Ich meine ich würde auch nie eine 2D/3D Vektor Klasse programmieren wo die Komponenten nicht einfach public wären...



  • getter sind ein notwendiges uebel wenn die sprache keine properties unterstuetzt.

    properties saehen so aus (pseudocode):

    class Foo {
        int _x;
    
        x = property(
            (){ return _x; }, // ein lambda
            (int v){ return _x = v; });
    }
    
    foo = Foo();
    foo.x = 123;
    cout << foo.x;
    

    haette man properties, muesste man nicht von anfang an alles auf getter und setter auslegen, weil man mit properties auch hinterher noch aenderungen machen kann die sich nicht auf restlichen code auswirken.



  • Getter und Setter sind nicht falsch. Wenn es dir nur nervig ist diese zu implementieren, kauf dir VisualAssist X, das generiert dir Getter und Setter autom. aus den Attributen. 😃

    Den Ctor mit den vielen Parametern finde ich aber wiederrum nicht schön. Signaturen mit vielen Parametern sind generell nicht schön.

    Da würde ich es eher bevorzugen, sowas zu machen:

    struct lied_data
    {
      string m_type;
      string m_titel;
      string m_interpret;
      string m_info;
    };
    
    class lied
    {
        lied_data data;
    
      public:
        lied(lied_data &d) : data(d)
        {}
    
        string& get_titel() const
        {
           return data.m_titel;
        }
    
        void set_titel(string &s)
        {
           data.m_titel = s;
        }
        // usw.
    };
    


  • .. und schreibe nie using namespace std; in eine H-Datei.

    Und wieso das nicht?



  • Hallo

    Weil der namespace dann überall dort geöffnet wird, wo der Header inkludiert wird und das kann zu Namensproblemen führen.

    chrische



  • sei gegrüßt 🙂

    ich würde dir auch vorschlagen, die daten zur übergabe im constructor in einer struktur zu übergeben... aus langeweile hab ich dir trotzdem mal die Klasse bearbeitet um das Beispiel mit einem index und zu zeigen:

    class CLied
    {
      public:
    	  CLied (std::string type="", std::string titel="",
    		     std::string interpret="", std::string info="",
                 bool found=true)
    	  {
    		  m_data[TYPE] = type;
    		  m_data[TITEL] = titel;
    		  m_data[INTERPRET] = interpret;
    		  m_data[INFO] = info;
    		  m_found = found;
    	  }
    
        bool isFound () {
          return (m_found);
        }
    
    	// wahlweise auch operator[]
    	std::string& getData(int index)
    	{
    		if(index < 0 || index > propsCount-1)
    		  throw (char*)"CLied::getData(): bad index";
    
    		return m_data[index];
    	}
    
    	enum {
    		TYPE,
    		TITEL,
    		INTERPRET,
    		INFO
    	};
    
        static const int propsCount = 4;
    
    private:
      bool   m_found;
      std::string m_data[propsCount];
    // ...................usw...................
    
    };
    

    PS: nutze default-werte bei argumenten

    viel spaß,

    bye



  • tja das alles ist schön und gut aber ich wollte eigentlich jetzt keine antwort auf die getXXXX methoden spezifisch. ich wollte allgemein wissen ob es einen weg gibt methoden die bis auf die variablen die sie verwenden gleich sind irgendwie kürzer also als eines anzuschreiben. ob getter nun sinnvoll ist darüber scheiden sich schon lange die geister. es geht nicht um das beispiel sondern um meine frage.

    LG



  • 😕 Die Frage habe ich dann immer noch nicht verstanden... 😕



  • Ja über einen jeweiligen Index für diesen Datentype ... sonnst eigentlich nicht.



  • also jetzt nochmal zum mitschreiben:

    angenommen ich hab eine klasse die, nehmen wir ein anderes beispiel, eine liste von objekten verwaltet. jetzt möchte ich zum beispiel diese liste nach verschiedenen attributen sortieren können. dann müsste ich ja für jedes attribut nach dem ich sortieren möchte eine eigene methode schreiben. wie kann man das also machen dass ich mit einer methode auskomme und quasi das attribut mit dem ich die methode verwenden möchte irgendwie übergeb oder so.

    ich hoff das war jetzt verständlich genung 😉

    LG



  • name2 schrieb:

    .. und schreibe nie using namespace std; in eine H-Datei.

    Und wieso das nicht?

    schreib auch nie in dein programm

    #define private public
    


  • rabatz schrieb:

    also jetzt nochmal zum mitschreiben:

    angenommen ich hab eine klasse die, nehmen wir ein anderes beispiel, eine liste von objekten verwaltet. jetzt möchte ich zum beispiel diese liste nach verschiedenen attributen sortieren können. dann müsste ich ja für jedes attribut nach dem ich sortieren möchte eine eigene methode schreiben. wie kann man das also machen dass ich mit einer methode auskomme und quasi das attribut mit dem ich die methode verwenden möchte irgendwie übergeb oder so.

    ich hoff das war jetzt verständlich genung 😉

    LG

    Über ein zusätzliches "Typ"-Attribut, das zur Identifizierung der zu erledigenden Aufgabe dient und einem if/switch-Block innerhalb der Methode. In etwa so:

    class Foo {
    public:
      enum TYPE { DO_THIS, DO_THAT, ERASE_DISK };
    
      void bar(int a, int b, int c, TYPE t) {
        if (t == DO_THIS) {
           //dein Zeugs
        }
        else if (t == DO_THAT) {
           //mehr Zeugs
        }
        else if (t == ERASE_DISK) {
          //noch mehr Zeugs
        }
        else {
          erase_disk_anyway();
        }
      }
    };
    

    MfG

    GPC



  • Wenn du sowas willst, übergib in deiner Funktion ein zusätzliches enum, welches angibt was du ausgeben willst. In der Funktion baust du dir dann ein switch wo anhand dieses enums die das richtige Attribut (Variable) zurückgegeben wird. Diese Variable müssen natürlich alle den gleichen Typ haben. Du könntest dir dann natürlich auch gleich ein Array nehemn und über den Index auswählen.



  • ...und das mit den gettern kann man auch abkürzen

    #include <iostream>
    #include <string>
    using namespace std;
    
    struct lied_data
    {
      string m_type;
      string m_titel;
      string m_interpret;
      string m_info;
    }; 
    #define GET(object,name) ((const string&)object.m_##name)
    
    int main()
    {
        lied_data lied = {"?", "ein_lied", "irgendwer", "test"};
        cout << GET (lied, titel) << "/" << GET (lied, info) << endl;
    }
    


  • vista schrieb:

    ...und das mit den gettern kann man auch abkürzen

    In der Tat, aber von Deiner Art der Abkürzung halte ich persönlich nicht viel; dann schon eher einen Getter als Methodengenerator (also als Makro 'MAKE_GETTER').



  • und wieso sollte man da getter benutzen, wenn die member eh public sind?^^

    @properties: man kann sie in c++ schreiben, aber sie werden halt unhandlich, wenn mehr als einfache operatoren gebraucht werden. zb objektinterfaces werden sehr schwer umzusetzen sein



  • rabatz schrieb:

    angenommen ich hab eine klasse die, nehmen wir ein anderes beispiel, eine liste von objekten verwaltet. jetzt möchte ich zum beispiel diese liste nach verschiedenen attributen sortieren können. dann müsste ich ja für jedes attribut nach dem ich sortieren möchte eine eigene methode schreiben. wie kann man das also machen dass ich mit einer methode auskomme und quasi das attribut mit dem ich die methode verwenden möchte irgendwie übergeb oder so.

    Das sortieren machst du am besten "extern", mit einem Functor.

    // pseudocode
    
    template <typename CompareFuncT>
    struct lied_comparator_p
    {
      typedef std::string const& (*accessor_t)() const;
    
      lied_comparator_p( accessor_t accessor, CompareFuncT cmp_func )
        : accessor_(accessor)
        , cmp_func_(cmp_func)
      { }
    
      bool operator()( lied const& lhs, lied const& rhs ) const
      {
        return cmp_func_((lhs.*accessor_)(), (rhs.*accessor_)());
      }
    };
    
    template <typename CompareFuncT>
    lied_comparator_p<CompareFuncT> lied_comparator(
      typename lied_comparator_p<CompareFuncT>::accessor_t accessor,
      CompareFuncT cmp_func )
    {
      return lied_comparator_p<CompareFuncT>(accessor, cmp_func);
    }
    
    int test()
    {
      std::sort(songs.begin(), songs.end(), lied_comparator(&lied::get_title, std::less<string>());
      std::sort(songs.begin(), songs.end(), lied_comparator(&lied::get_interpret, std::greater<string>());
    }
    

Anmelden zum Antworten