get/set per Makro



  • Hoi 🙂

    Ich habe gerade nervt etwas Code von mir portiert und musste Unmengen an gettern/settern schreiben.

    Da dachte ich mir ich mach einfach mal ein Makro dafür:

    #define DECLAREVAR_R(description, type, name) \
        type name  ; \
        public: \
        type get ## description  () { return name; } \
        private:
    
    #define DECLAREVAR_W(description, type, name) \
        type name  ; \
        public: \
        void set ## description ( type val ) { name = val; } \
        private:
    
    #define DECLAREVAR_RW(description, type, name) \
        type name  ; \
        public: \
        type get ## description  () { return name; } \
        void set ## description ( type val ) { name = val; } \
        private:
    
    #include <iostream>
    
    class Test
    {
        DECLAREVAR_RW(Test, unsigned int, m_test)
    };
    
    int main()
    {
        Test test;
        test.setTest(0xDEADBEEF);
        std::cout << test.getTest() << std::endl;
    }
    

    Ich denke schon dass man mich dafür mit Mistgabeln & Fackeln jagen wird 🙂
    Falls es so ist, bitte sagen was daran schlecht ist, ich finde den Ansatz gerade recht gut & praktisch.

    Grüße,
    Ethon



  • Das Makro wird selbstverständlich nur für POD-Typen verwendet von daher ist fehlende Übergabe per Referenz kein Grund 🙂



  • Ethon schrieb:

    Das Makro wird selbstverständlich nur für POD-Typen verwendet von daher ist fehlende Übergabe per Referenz kein Grund 🙂

    Wenns wirklich PODs sind, dann kannst du dir die Getter/Setter doch gleich sparen? 😉



  • Ethon schrieb:

    Das Makro wird selbstverständlich nur für POD-Typen verwendet von daher ist fehlende Übergabe per Referenz kein Grund 🙂

    Das hat nichts mit PODs zu tun. Generell übergibt man grössere Objekte eher als Referenz und kleinere eher als Kopie. Doch POD-Objekte können klein und gross sein.

    Im Übrigen darf ein POD-Objekt nicht verschiedene Zugriffsbereiche ( public , private ) haben.



  • Upps, mir ist ein kleiner Patzer unterlaufen.
    Hab eben im PODs falsch assoziert.

    Es werden einfach nur built-in Basistypen wie zb int, float sowie Zeiger und Referenzen gespeichert.

    Und Getter brauche ich ziemlich oft, was allein schon in einer Klassendefinition mit Rücksicht auf Windows, Linux und MacOSX knapp 30 Zeilen gespart hat ...



  • Ich mag die Idee, weil man sich so die Tipparbeit spart, die sonst nötig ist, um sich die Möglichkeit offen zu halten, die Interna später zu bearbeiten, ohne das Interface der Klasse ändern zu müssen.



  • Dobi schrieb:

    Ich mag die Idee, weil man sich so die Tipparbeit spart, die sonst nötig ist, um sich die Möglichkeit offen zu halten, die Interna später zu bearbeiten, ohne das Interface der Klasse ändern zu müssen.

    Benutz eine IDE die das automatisch für dich macht.

    Makros für sowas sind eine dumme idee.



  • Wenn du soviele Getter und Setter hast dass du das brauchst solltest du definitiv dein Design überdenken wenn du mich fragst...



  • Dobi schrieb:

    Ich mag die Idee, weil man sich so die Tipparbeit spart, die sonst nötig ist, um sich die Möglichkeit offen zu halten, die Interna später zu bearbeiten, ohne das Interface der Klasse ändern zu müssen.

    Äh wie? Mit den Makros kannst du gar keine Interna ändern. Und jede kleinste Änderung an den Makros erfordert die Rekompilierung von allen Clients, die so eine Klasse verwenden. Und zwar für alle Klassen, auch wenn die Änderung nur eine Klasse betrifft.

    Abgesehen davon kann man mit den Makros nur Trivialmethoden bauen. Ein assert() , das ich in Settern z.B. ab und zu verwende, ist nicht möglich. Oder ein Aufruf einer anderen Funktion.



  • Ethon schrieb:

    Ich denke schon dass man mich dafür mit Mistgabeln & Fackeln jagen wird 🙂
    Falls es so ist, bitte sagen was daran schlecht ist, ich finde den Ansatz gerade recht gut & praktisch.

    Auf der einen Seite: Makros, die einfach nur Schreibarbeit sparen, sind völlig in Ordnung. Da gibts genug Anwendungen für, um z.B. umständlichen Template-Code lesbarer zu gestalten.

    Auf der anderen Seite:
    - Pauschal per Makro jedem Attribut triviale Getter und Setter zu verpassen widerspricht dem Konzept der Kapselung. Da kannst du die Attribute auch gleich public machen. Okay, du hast auch Readonly on Writeonly mit drin. Wobei letzteres in meinen Augen wenig Sinn macht. Wenn man mit einem trivialen Setter einen Wert ohne weitere Nebenwirkungen und Prüfungen ändern kann, warum sollte man ihn dann nicht lesen dürfen?
    - Die Makros werden sofort nutzlos, wenn die Signatur nicht mehr ganz stimmt. Z.B. sollten Getter const sein - außer wenns um Referenzen geht. Dann sollten es entweder konstante Referenzen sein oder der Getter selbst nicht const.
    - Die Makros machen Probleme, wenn du später ein Problem im Programm hast und dich fragst, wo zum Henker Test.m_test plötzlich auf 2 gesetzt wird, obwohl es doch eigentlich immer 1 sein sollte. Mit dem Makro kannst du nämlich leider keinen Breakpoint mehr in Test::setTest() setzen um diese eine Stelle zu finden.

    Mein Fazit: grundsätzlich eine nette Idee, nur werden wirklich triviale getter/setter so selten benötigt, dass der wenige gesparte Aufwand beim Tippen die Nachteile des Makros nicht wirklich wett machen.



  • pumuckl schrieb:

    Okay, du hast auch Readonly on Writeonly mit drin. Wobei letzteres in meinen Augen wenig Sinn macht. Wenn man mit einem trivialen Setter einen Wert ohne weitere Nebenwirkungen und Prüfungen ändern kann, warum sollte man ihn dann nicht lesen dürfen?

    Eventuell könnte man sich dann seine eigene Getter-Funktion schreiben, die auf z.B. NULL prüft oder sonst etwas spezielles durchführt.



  • Shade Of Mine schrieb:

    Benutz eine IDE die das automatisch für dich macht.
    Makros für sowas sind eine dumme idee.

    Wenn VC 2005 Express das könnte, wärs schön. 😉

    dot schrieb:

    Wenn du soviele Getter und Setter hast dass du das brauchst solltest du definitiv dein Design überdenken wenn du mich fragst...

    Stimmt wohl.

    Nexus schrieb:

    Äh wie? Mit den Makros kannst du gar keine Interna ändern. Und jede kleinste Änderung an den Makros erfordert die Rekompilierung von allen Clients, die so eine Klasse verwenden. Und zwar für alle Klassen, auch wenn die Änderung nur eine Klasse betrifft.
    Abgesehen davon kann man mit den Makros nur Trivialmethoden bauen. Ein assert() , das ich in Settern z.B. ab und zu verwende, ist nicht möglich. Oder ein Aufruf einer anderen Funktion.

    Sorry, da hab ich mich wohl falsch ausgedrückt. Ich meinte nicht, dass man mit dem Makro etwas ändert, aber falls ich für z.B. GetQuersumme einer RiesenInteger-Klasse auf lazy initialization umsteigen will, müssen die Clients natürlich neukompilieren, aber nix ändern, um Gegensatz dazu, wenn das Member direkt public wär.

    Aber gut, ich fand auch eher den Makrozirkus an sich lustig, weil ichs zum ersten mal so gesehen hab. 🙂


Anmelden zum Antworten