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 .