c++ - Should i make a class instead of the repetitive get/set statements? -


consider following code (which simplified version of original one):

#include <string>  namespace {     class ctype; }  class my::ctype { private:      std::string simple_name;  public:      explicit ctype(std::string simple_name)     : simple_name{std::move(requireidentifier(simple_name))} // duplicate code     {     }     std::string get_simple_name() const     {         return simple_name;     }     void set_simple_name(std::string value)     {         simple_name = std::move(requireidentifier(value)); // duplicate code     } }; 

the requireidentifier function returns reference value value not empty otherwise throw std::invalid_argument exception.

i have many classes similar ctype class definition, of them have private member variable of type std::string , subsequently check value not empty following expression:

std::move(requireidentifier(value)) 

here problem, repeated in of classes! suppose have 10 classes similar ctype, there should 20=2*10 expressions above case! don't want repeat similar code in of 20 places of code! seams wrong.

i think should define new class type:

class my::identifier { private:      std::string name;  public:      explicit identifier(std::string name)     : name{std::move(requireidentifier(name))} // duplicate code     {     }     std::string get() const     {         return name;     }     void set(std::string value)     {         name = std::move(requireidentifier(value)); // duplicate code     } }; 

and change definition of ctype class following code:

class my::ctype { private:      identifier simple_name;  public:      explicit ctype(identifier simple_name)     : simple_name{std::move(simple_name)}     {     }     identifier get_simple_name() const     {         return simple_name;     }     void set_simple_name(identifier value)     {         simple_name = std::move(value);     } }; 

btw, can't avoid repetitive std::move section , not problem.

but if don't overload = operator of identifier class , if don't declare implicit conversion std::string identifier class, identifier class not work string class. isn't bad choice of design? proper way avoid repetitive code in such case (afaik, shouldn't subclass stl container)?

edit: requireidentifier function defined following code:

inline std::string& my::requestidentifier(std::string& value) {     for(char c : value)     {         if(!isalnum(c) && c != '_')         {             throw std::invalid_argument{""};         }     }      return value; }  inline std::string& my::requireidentifier(std::string& value) // here {     if(value.empty())     {         throw std::invalid_argument{""};     }     else     {         return my::requestidentifier(value);     } } 

conclusion

as can see if put "extraction" of underlying string in ctype class (as mentioned in accepted answer tony d), , if want work string type, have call get , set member functions of identifier class in of 10 classes repetitively had called requireidentifier function. therefore making class eliminating 1 function call redundancy, techinically not approach.

on other hand , regardless of code redundancy, should declare identifer class if think new type string type cannot represent well, , can declare implicit user-defined constructor make compatible string type, , purpose of identifier class not get , set accessor string type, purpose new type.

but if don't overload = operator of identifier class , if don't declare implicit conversion std::string identifier class, identifier class not work string class. isn't bad choice of design? proper way avoid repetitive code in such case?

so... put "extraction" of underlying string in ctype class:

class my::ctype {   private:     identifier simple_name;    public:     explicit ctype(identifier simple_name)       : simple_name{std::move(simple_name)}     { }      std::string get_simple_name() const     {         return simple_name.get();     }      void set_simple_name(std::string value)     {         simple_name.set(std::move(value));     } }; 

update: requested in comments, below - illustration of using check_invariants() function. there's still redundancy, can repeat arbitrary number of checks without further modifying each mutating function.

class my::ctype {   private:     std::string simple_name;      void check_invariants()     {         if (!is_identifier(simple_name))             throw std::invalid_argument("empty identifier);     }    public:     explicit ctype(std::string simple_name)       : simple_name{std::move(simple_name))     {          check_invariants();     }     std::string get_simple_name() const     {         return simple_name;     }     void set_simple_name(std::string value)     {         simple_name = std::move(value);         check_invariants();     } }; 

...with...

bool is_identifier(const std::string& s) {     return !s.empty() &&         (isalpha(s[0]) || s[0] == '_') &&         std::all_of(s.begin() + 1, s.end(), [](char c) { return isalnum(c) || c == '_'; }); } 

Comments

Popular posts from this blog

javascript - Jquery show_hide, what to add in order to make the page scroll to the bottom of the hidden field once button is clicked -

javascript - Highcharts multi-color line -

javascript - Enter key does not work in search box -