Implémentation de propriété en C ++

Bonjour à tous! Lors de l'implémentation de projets, les développeurs ont souvent besoin de classes qui ne contiennent que des champs et n'ont aucune fonction. Ces classes sont utiles pour stocker les informations nécessaires avec leurs manipulations ultérieures.

La première approche pour implémenter de telles classes est basée sur l'utilisation de structures C. Comme inconvénient de cette approche, c'est que tous les champs sont accessibles en écriture et en lecture, ce qui n'est pas toujours bon.

struct person { int id; human type; std::string name; std::string address[5]; bool merried; }; 

La deuxième approche est basée sur le masquage de tous les champs et la mise à disposition de getters et setters pour les champs. Cette approche est très utilisée dans le langage Java. Comme avantage, nous pouvons contrôler l'accès aux champs. Les inconvénients incluent le fait que la classe devient grande et que les getters et setters ne portent pas de fardeau logique.

 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; }; 

Si le champ est un type de classe, vous devez parfois définir l'objet par valeur, par lvalue-link, par rvalue-link. Et aussi en utilisant des modificateurs const / volatile.

 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; }; 

De nombreuses langues prennent en charge les propriétés en tant que fonction de langue. L'écriture de code devient plus propre et plus fiable. Pour simplifier l'écriture des getters et setters, vous pouvez utiliser des macros pour générer du code.

 #define SETTER_PRIM(type, name) \ void set_##name(type value) { \ this->name = value; \ } #define GETTER_PRIM(type, name) \ type get_##name() const { \ return name; \ } 

Mais l'utilisation de macros est dangereuse. Il se peut que nous n'indiquions pas correctement le type (type) ou une variable de mauvais type (nom). Dans le meilleur des cas, nous obtenons une erreur d'exécution lors de l'utilisation des getters et setters. Dans le pire des cas, l'erreur restera.

Je voulais que nous puissions générer des getters et des setters, mais en même temps, nous pouvions vérifier l'exactitude du type, l'exactitude du type avec la variable (nom) et que les types étaient égaux. Et cela peut être fait à partir de C ++ 11 en utilisant la bibliothèque standard type_traits.

 #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; \ } 

En utilisant cette approche, vous pouvez implémenter des getters et setters pour tous les types de champs de classe.

  • types primitifs
  • types d'objets
  • les transferts
  • tableau
  • pointeurs
  • liens

Toutes les macros pour les getters et setters implémentées sous la forme d'une bibliothèque uniquement en-tête. En connectant un seul fichier d'en-tête, vous pouvez facilement implémenter une classe de date avec tous les getters et setters nécessaires.

 #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; }; 

Le code source de la bibliothèque open source peut être consulté ici à ce lien .

Source: https://habr.com/ru/post/fr459212/


All Articles