Hallo allerseits! Bei der Implementierung von Projekten benötigen Entwickler häufig Klassen, die nur Felder enthalten und keine Funktionen haben. Solche Klassen sind nützlich, um die erforderlichen Informationen bei ihren nachfolgenden Manipulationen zu speichern.
Der erste Ansatz zur Implementierung solcher Klassen basiert auf der Verwendung von C-Strukturen. Als Nachteil dieses Ansatzes ist es, dass alle Felder beschreibbar und lesbar sind, was nicht immer gut ist.
struct person { int id; human type; std::string name; std::string address[5]; bool merried; };
Der zweite Ansatz basiert darauf, alle Felder auszublenden und Getter und Setter für die Felder bereitzustellen. Dieser Ansatz wird in der Java-Sprache sehr häufig verwendet. Als Vorteil können wir den Zugriff auf Felder steuern. Zu den Nachteilen gehört die Tatsache, dass die Klasse groß wird und Getter und Setter keine logische Belastung tragen.
class person { public: void set_id(int id) { this->id = id; } int get_id() const { return id; } void set_merried(bool merried) { this->merried = merried; } bool is_merried() const { return merried; } void set_type(human type) { this->type = type; } human get_type() const { return type; } void set_name(const std::string& name) { this->name = name; } const std::string& get_name() const { return name; } private: int id; human type; std::string name; std::string address[5]; bool merried; };
Wenn das Feld ein Klassentyp ist, müssen Sie das Objekt manchmal nach Wert, nach lvalue-link, nach rvalue-link festlegen. Und auch mit const / flüchtigen Modifikatoren.
class person { public: void set_name(const std::string& name) { this->name = name; } void set_name(std::string&& name) { this->name = std::move(name); } const std::string& get_name() const { return name; } private: int id; human type; std::string name; std::string address[5]; bool merried; };
Viele Sprachen unterstützen Eigenschaften als Sprachfunktion. Das Schreiben von Code wird sauberer und zuverlässiger. Um das Schreiben von Gettern und Setzern zu vereinfachen, können Sie Makros verwenden, um Code zu generieren.
#define SETTER_PRIM(type, name) \ void set_##name(type value) { \ this->name = value; \ } #define GETTER_PRIM(type, name) \ type get_##name() const { \ return name; \ }
Die Verwendung von Makros ist jedoch gefährlich. Möglicherweise geben wir den Typ (Typ) oder eine Variable des falschen Typs (Name) nicht korrekt an. Im besten Fall erhalten wir einen Laufzeitfehler, wenn Getter und Setter verwendet werden. Im schlimmsten Fall bleibt der Fehler bestehen.
Ich wollte, dass wir Getter und Setter generieren können, aber gleichzeitig konnten wir die Richtigkeit des Typs (Typ), die Richtigkeit des Typs mit einer Variablen (Name) und die Gleichheit der Typen überprüfen. Dies kann ab C ++ 11 mithilfe der Standardbibliothek type_traits erfolgen.
#define SETTER_PRIM(type, name) \ void set_##name(type value) { \ using T1 = type; \ using T2 = decltype(name); \ static_assert(std::is_fundamental<T1>::value, \ "only primitive types"); \ static_assert(std::is_fundamental<T2>::value, \ "variable must be primitive"); \ static_assert(std::is_same<T1, T2>::value, \ "both types must be same"); \ this->name = value; \ } #define GETTER_PRIM(type, name) \ type get_##name() const { \ using T1 = type; \ using T2 = decltype(name); \ static_assert(std::is_fundamental<T1>::value, \ "only primitive types"); \ static_assert(std::is_fundamental<T2>::value, \ "variable must be primitive"); \ static_assert(std::is_same<T1, T2>::value, \ "both types must be same"); \ return name; \ }
Mit diesem Ansatz können Sie Getter und Setter für alle Arten von Klassenfeldern implementieren.
- primitive Typen
- Objekttypen
- Transfers
- Array
- Zeiger
- Links
Alle Makros für Getter und Setter, die in Form einer Nur-Header-Bibliothek implementiert sind. Indem Sie nur eine Header-Datei verbinden, können Sie problemlos eine Datumsklasse mit allen erforderlichen Gettern und Setzern implementieren.
#include "property.hpp" class person { public: person() = default; ~person() = default; SETTER_PRIM(int, id); SETTER_FLAG(bool, merried); SETTER_ENUM(human, type); SETTER_PTR(int, next); SETTER_ARR(std::string, address, 3); SETTER_OBJ_LR(std::string, name); SETTER_OBJ_CLR(std::string, name); SETTER_OBJ_RR(std::string, name); GETTER_PRIM(int, id); GETTER_FLAG(bool, merried); GETTER_ENUM(human, type); GETTER_OBJ_LR(std::string, name); GETTER_OBJ_CLR(std::string, name); GETTER_PTR(int, next); GETTER_ARR(std::string, address); private: int id; human type; std::string name; std::string address[5]; bool merried; int* next; };
Der Quellcode der Open Source-Bibliothek kann hier unter diesem
Link eingesehen werden.