📜 ⬆️ ⬇️

Implementing properties in C ++

Hello! When implementing projects, developers often need classes that contain only fields and have no functions. Such classes are useful for saving necessary information and their subsequent manipulations.

The first approach in the implementation of such classes is based on the use of C structures. As a disadvantage of this approach, it is that all the fields are readable and readable, which is not always good.

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

The second approach is based on hiding all the fields and providing getters and setters for the fields. This approach is vividly used in the Java language. As an advantage, we can highlight the fact that we can control access to the fields. The disadvantages include the fact that the class becomes large, and the getters and setters do not carry the logical load.
')
 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; }; 

In case there is a class type field, sometimes you need to set an object by value, by lvalue-link, by rvalue-link. And also with the use of const / volatile modifiers.

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

Many languages ​​support properties as a language feature. Code writing becomes cleaner and more reliable. To simplify writing getters and setters, you can use macros to generate 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; \ } 

But using macros is dangerous. We may not correctly indicate the type (type) or variable of the wrong type (name). In the best case, we get a time error of execution when using getters and setters. In the worst case, the error will remain.

It would be desirable that we could generate getters and setters, but at the same time we could check the correctness of the type (type), the correctness of the type of the variable (name) and that the types were equal. And this can be done starting with C ++ 11 using the standard library 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; \ } 

Using this approach, it is possible to implement getters and setters for all types of class fields.


All macros for getters and setters implemented in the form of a header-only library. By connecting only one header file, you can easily implement a date class with all the necessary getters and setters.

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

The source code of the open source library can be found here via this link .

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


All Articles