Hola a todos! Al implementar proyectos, los desarrolladores a menudo necesitan clases que contienen solo campos y no tienen ninguna función. Dichas clases son útiles para almacenar la información necesaria con sus manipulaciones posteriores.
El primer enfoque para implementar tales clases se basa en el uso de estructuras C. Como inconveniente de este enfoque, es que todos los campos se pueden escribir y leer, lo que no siempre es bueno.
struct person { int id; human type; std::string name; std::string address[5]; bool merried; };
El segundo enfoque se basa en ocultar todos los campos y proporcionar captadores y establecedores para los campos. Este enfoque se usa vívidamente en el lenguaje Java. Como ventaja, podemos controlar el acceso a los campos. Las desventajas incluyen el hecho de que la clase se vuelve grande, y los captadores y establecedores no llevan una carga lógica.
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 el campo es un tipo de clase, a veces necesita establecer el objeto por valor, por lvalue-link, por rvalue-link. Y también usando const / modificadores volátiles.
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; };
Muchos idiomas admiten propiedades como una característica de idioma. Escribir código se vuelve más limpio y más confiable. Para simplificar la escritura de getters y setters, puede usar macros para generar 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; \ }
Pero usar macros es peligroso. Es posible que no indiquemos correctamente el tipo (tipo) o una variable del tipo incorrecto (nombre). En el mejor de los casos, obtenemos un error de tiempo de ejecución cuando usamos getters y setters. En el peor de los casos, el error permanecerá.
Quería que pudiéramos generar captadores y establecedores, pero al mismo tiempo podríamos verificar la corrección del tipo, la corrección del tipo con la variable (nombre) y que los tipos eran iguales. Y esto se puede hacer comenzando con C ++ 11 usando la biblioteca estándar 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; \ }
Con este enfoque, puede implementar captadores y establecedores para todos los tipos de campos de clase.
- tipos primitivos
- tipos de objeto
- transferencias
- matriz
- punteros
- enlaces
Todas las macros para getters y setters implementadas en forma de una biblioteca de solo encabezado. Al conectar solo un archivo de encabezado, puede implementar fácilmente una clase de fecha con todos los captadores y establecedores necesarios.
#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; };
El código fuente de la biblioteca de código abierto se puede ver aquí en este
enlace .