Первый подход в реализации таких классов основан на использовании С структур. Как недостаток этого подхода, это то что все поля доступные на запись и чтения, что не всегда хорошо.
struct person { int id; human type; std::string name; std::string address[5]; bool merried; };
Второй подход основан на скрытии всех полей и предоставлении для полей геттеров и сеттеров. Этот подход ярко используется в языке Java. В качестве преимущества можно выделить то, что мы можем управлять доступом к полям. К недостаткам можно отнести, то что класс стает большим, а геттеры и сеттеры не несут логической нагрузки.
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; };
В случае если поле типа класса, иногда нужно устанавливать объект по значению, по lvalue-ссылке, по rvalue-ссылке. А также с применением модификаторов 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; };
Много языков поддерживают свойства как языковую фичу. Написание кода становиться чище и надежнее. Чтобы упростить написание геттеров и сеттеров можно использовать макросы для генерации кода.
#define SETTER_PRIM(type, name) \ void set_##name(type value) { \ this->name = value; \ } #define GETTER_PRIM(type, name) \ type get_##name() const { \ return name; \ }
Но использование макросов опасно. Мы можем не верно указать тип (type) или переменную не того типа (name). В лучшем случае получим ошибку времени исполнении при использовании геттеров и сеттеров. В худшем случае ошибка останется.
Хотелось чтобы мы могли генерировать геттеры и сеттеры, но при этом могли проверить корректность типа (type), корректность типа переменой (name) и чтобы типы были равны. И это можно сделать начиная с С++11 используя 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; \ }
Используя данный подход можно реализовать геттеры и сеттеры для всех типов полей класса.
- примитивных типов
- объектных типов
- перечисления
- массива
- указателей
- ссылок
Все макросы для геттеров и сеттеров реализовал в виде header-only библиотеки. Подключив только один заголовочный файл можно легко реализовать дата класс со всеми необходимыми геттерами и сеттерами.
#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; };
Исходный код библиотечки с открытым кодом можно посмотреть вот по этой ссылке.
ссылка на оригинал статьи https://habr.com/ru/post/459212/
Добавить комментарий