Zu faul für get & set Methoden?
-
Grundsätzlich sollte man bestrebt sein, setter zu vermeiden, insbesondere solche, die ein ganz bestimmtes Datenelement ändern. Das ist dann kaum noch besser wie public, man kann vielleicht noch den Wertebereich prüfen.
Am besten ist es, man schreibt sich imutable classes wo immer möglich, IMO.
-
Klar, dass man setter auf ein bestimmtes Element vermeiden sollte, weil dies dem Gedanken des information hiding widerstrebt. Allerings kannst du nicht immer mit immutable classes glücklich werden, so dass setter notwendig werden. Ich plädiere allerdings dafür die Kreativität zu bemühen und sprechende Namen zu verwenden statt dem langweiligen get/set-Kram. Den kann man immer noch nehmen wenn die Kreativität einmal versagen sollte
.
-
hgf schrieb:
Mit einer Member-Funktion
TYP& xvar() { return _xvar; }
habe ich gleichzeitig get und set Funktionalität.
Nein, nicht so richtig. Der eigentliche Vorteil von get/set-Methoden ist, dass das Objekt selber kontrollieren und beobachten kann, wann und *wie* darauf zugegriffen wird. Deine Methode kannst du fast mit einer public-Variablen ersetzen.
-
warum nicht so etwas wie properties? Mit Templates kann man das doch leicht machen
#ifndef PROPERTIES_HH #define PROPERTIES_HH namespace props { template<typename T> struct nothing { static void set(T &) { } }; template<typename T, class Policy=nothing<T> > class propertie { T obj_m; propertie(const propertie<T,Policy> &); propertie<T> operator=(const propertie<T,Policy> &); public: operator T() { return obj_m; } operator const T() { return obj_m; } const T &operator*() const { return obj_m; } T &operator*() { return obj_m; } template<typename Y, class Set_2> propertie<T,Policy> & operator=(const propertie<Y,Set_2> &obj) { if(&obj!=this) { obj_m=obj; Policy::set(obj_m); } return *this; } template<typename Y> propertie<T,Policy> &operator=(const Y &obj) { Policy::set(obj_m=obj); return *this; } template<typename Y> propertie(const Y &obj) : obj_m(obj) { Policy::set(obj_m); } template<typename Y> propertie(const propertie<Y> &obj) : obj_m(obj) { Policy::set(obj_m); } propertie() { } }; } #endif
#include "properties.hh" #include <iostream> using namespace props; struct foo { }; struct demo1 { propertie<int> i; propertie<int,demo1> j; propertie<foo> f; demo1() : i(1) { } template<typename Char,class Char_traits> void out(std::basic_ostream<Char,Char_traits> &o) const { o << "i:=" << *i << " j:=" << *j; } static void set(int &j) { j%=5; } }; template<typename Char,class Traits> std::basic_ostream<Char,Traits> &operator<<(std::basic_ostream<Char,Traits> &o, const demo1 &obj) { obj.out(o); return o; } int main() { demo1 obj; obj.j=11; std::cout << obj << std::endl; }
-
Nachdem ich jetzt erstmal indent rüberlaufen lassen musste um den Code zu entschlüsseln, sieht das für mich ziemlich unbrauchbar aus. Was machst du, wenn eine Klasse mehrere Properties hat? Ausserdem fehlt dort noch die Möglichkeit auf get zu reagieren.
Wenn dann, müsste das in der Anwendung so aussehen:
class Foo { property<Foo, int> x; Foo() : x(this, &Foo::get_x, &Foo::set_x, 0) { } ... };
Dann kommt noch das Problem, wenn 'x' hier jetzt eine Klasse wäre, deren Konstruktor mehrere Argumente nimmt.
Aber dann doch lieber get/set-Methoden definieren und dabei gleich drüber nachdenken, ob man die Schnittstelle nicht gleich anders definiert.
-
Nachdem ich jetzt erstmal indent rüberlaufen lassen musste um den Code zu entschlüsseln, sieht das für mich ziemlich unbrauchbar aus. Was machst du, wenn eine Klasse mehrere Properties hat? Ausserdem fehlt dort noch die Möglichkeit auf get zu reagieren.
Dann nimmst du eben nicht Kingruedis Properties, sondern meine. (Sind grad nicht online, wegen eines Umzugs).
-
Willst du mal ein Anwendungsbeispiel posten? Mein Beispiel könnte ich selber implementieren, nur was mir daran und an Kings Code nicht gefällt, ist dass man mit dem *-Operator (oder anderer Methode) darauf zugreifen muss. Hm, man könnte vielleicht einen operator T(); definieren...
Und bei dem was ich im Kopf habe, fehlt da noch ein Weg, zur Compilezeit festlegen zu können, ob man nur get oder nur set, oder beides haben will.
-
Was machst du, wenn eine Klasse mehrere Properties hat?
naja, man kann für jeden Typ ja eigene propertie-policies definieren. Ich hab in dem Beispiel nur einfach die eigene Klasse direkt als propertie-policie benutzt
Ausserdem fehlt dort noch die Möglichkeit auf get zu reagieren.
das kannst du ja ruck-zuck einbauen.
und an Kings Code nicht gefällt, ist dass man mit dem *-Operator (oder anderer Methode) darauf zugreifen muss. Hm, man könnte vielleicht einen operator T();
das hab ich doch implementiert
-
hab mal die Änderungen eingefügt
#ifndef PROPERTIES_HH #define PROPERTIES_HH namespace props { template<typename T> struct nothing { static void set(T &) { } static T get(const T &t) { return t; } }; template<typename T, class Set_policy=nothing<T>, class Get_policy=nothing<T> > class property { T obj_m; property(const property<T,Set_policy,Get_policy> &); property<T> operator=(const property<T,Set_policy,Get_policy> &); public: operator const T() const { return Get_policy::get(obj_m); } const T operator*() const { return Get_policy::get(obj_m); } template<typename Y, class Set, class Get> property<T,Set_policy,Get_policy> & operator=(const property<Y,Set,Get> &obj) { if(&obj!=this) { obj_m=obj; Set_policy::set(obj_m); } return *this; } template<typename Y> property<T,Set_policy,Get_policy> &operator=(const Y &obj) { Set_policy::set(obj_m=obj); return *this; } template<typename Y> property(const Y &obj) : obj_m(obj) { Set_policy::set(obj_m); } template<typename Y,class Set,class Get> property(const property<Y,Set,Get> &obj) : obj_m(obj) { Set_policy::set(obj_m); } property() { } }; } #endif
#include "properties.hh" #include <iostream> using namespace props; struct foo { }; struct demo1 { struct get_policy { static int get(int i) { return i+1; } }; static void set(int &j) { j%=5; } property<int,nothing<int>,get_policy> i; property<int,demo1> j; property<foo> f; demo1() : i(1) { } template<typename Char,class Char_traits> void out(std::basic_ostream<Char,Char_traits> &o) const { o << "i:=" << i << " j:=" << j; } }; template<typename Char,class Traits> std::basic_ostream<Char,Traits> &operator<<(std::basic_ostream<Char,Traits> &o, const demo1 &obj) { obj.out(o); return o; } int main() { demo1 obj; obj.j=11; std::cout << obj << std::endl; }
-
kingruedi schrieb:
naja, man kann für jeden Typ ja eigene propertie-policies definieren. Ich hab in dem Beispiel nur einfach die eigene Klasse direkt als propertie-policie benutzt
ja schon, aber dann muss man wieder die Kommunikation zw. der Property-Besitzer-Klasse und dem get/set-Strukt schaffen.
Hm, man könnte vielleicht einen operator T();
das hab ich doch implementiert
Stimmt, hab ich übersehen. Der *-Operator müsste *obj_m zurückliefern (bzw. *get(obj_m)). Oder hast du das absichtlich gemacht, damit man kontrollieren kann, ob eine Kopie oder eine Referenz zurückgegeben wird? Ist dann etwas ungewöhnlich wenn man **x schreiben muss, um zu dereferenzieren.
// hm, in der ersten Version gibst du bei *() noch eine Referenz zurück, bei der zweiten das selbe wie bei T()...