Implementação de propriedade em C ++

Olá pessoal! Ao implementar projetos, os desenvolvedores geralmente precisam de classes que contenham apenas campos e não tenham nenhuma função. Essas classes são úteis para armazenar as informações necessárias com suas manipulações subseqüentes.

A primeira abordagem para implementar essas classes é baseada no uso de estruturas C. Como uma desvantagem dessa abordagem, todos os campos são graváveis ​​e legíveis, o que nem sempre é bom.

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

A segunda abordagem é baseada em ocultar todos os campos e fornecer getters e setters para os campos. Essa abordagem é vividamente usada na linguagem Java. Como vantagem, podemos controlar o acesso aos campos. As desvantagens incluem o fato de que a classe se torna grande e os getters e setters não carregam um fardo lógico.

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

Se o campo for um tipo de classe, às vezes você precisará definir o objeto por valor, por lvalue-link, por rvalue-link. E também usando modificadores const / voláteis.

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

Muitos idiomas suportam propriedades como um recurso de idioma. Escrever código se torna mais limpo e mais confiável. Para simplificar a gravação de getters e setters, você pode usar macros para gerar código.

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

Mas usar macros é perigoso. Podemos não indicar corretamente o tipo (tipo) ou uma variável do tipo errado (nome). Na melhor das hipóteses, obtemos um erro de tempo de execução ao usar getters e setters. Na pior das hipóteses, o erro permanecerá.

Eu queria que pudéssemos gerar getters e setters, mas, ao mesmo tempo, poderíamos verificar a correção do tipo (tipo), a correção do tipo com uma variável (nome) e se os tipos eram iguais. E isso pode ser feito a partir do C ++ 11 usando a biblioteca padrão 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; \ } 

Usando essa abordagem, você pode implementar getters e setters para todos os tipos de campos de classe.

  • tipos primitivos
  • tipos de objetos
  • transferências
  • matriz
  • ponteiros
  • ligações

Todas as macros para getters e setters implementadas na forma de uma biblioteca somente de cabeçalho. Ao conectar apenas um arquivo de cabeçalho, você pode implementar facilmente uma classe de data com todos os getters e setters necessários.

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

O código fonte da biblioteca de código aberto pode ser visualizado aqui neste link .

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


All Articles