Simple C++ getter/setters

c++, class

Solution

- Generally using accessors/mutators at all is a design smell that your class public interface is incomplete. Typically speaking you want a useful public interface that provides meaningful functionality rather than simply get/set (which is just one or two steps better than we were in C with structs and functions). Every time you want to write a mutator, and many times you want to write an accessor first just take a step back and ask yourself `"do I *really* need this?"`.

- Just idiom-wise people may not be prepared to expect such a function so it will increase a maintainer's time to grok your code.

- The same-named methods are almost the same as the public member: just use a public member in that case. When the methods do two different things, name them two different things.

- The "mutator" returning by non-const reference would allow for a wide variety of aliasing problems where someone stashes off an alias to the member, relying on it to exist later. By using a separate setter function you prevent people from aliasing to your private data.

Problem

Lately I'm writing my getter and setters as (note: real classes do more things in getter/setter): ``` struct A { const int& value() const { return value_; } // getter int& value() { return value_; } // getter/setter private: int value_; }; ``` which allows me to do the following: ``` auto a = A{2}; // non-const object a // create copies by "default" (value always returns a ref!): int b = a.value(); // b = 2, is a copy of value :) auto c = a.value(); // c = 2, is a copy of value :) // create references explicitly: auto& d = a.value(); // d is a ref to a.value_ :) decltype(a.value()) e = a.value(); // e is a ref to a.value_ :) a.value() = 3; // sets a.value_ = 3 :) cout << b << " " << c << " " << d << " " << e << endl; // 2 2 3 3 const auto ca = A{1}; const auto& f = ca.value(); // f is a const ref to ca.value_ :) auto& g = ca.value(); // no compiler error! :( // g = 4; // compiler error :) decltype(ca.value()) h = ca.value(); // h is a const ref to ca.value_ :) //ca.value() = 2; // compiler error! :) cout << f << " " << g << " " << h << endl; // 1 1 1 ``` This approach doesn't allow me to: - validate the input for the setter (which is a big BUT), - return by value in the const member function (because I want the compiler to catch assignment to const objects: `ca.value() = 2`). Update: see cluracan answer below. However, I'm still using this a lot because - most of the time I don't need that, - this allows me to decouple the implementation details of my classes from their interface, which is just what I want. Example: ``` struct A { const int& value(const std::size_t i) const { return values_[i]; } int& value(const std::size_t i) { return values_[i]; } private: std::vector<int> values_; // Storing the values in a vector/list/etc is an implementation detail. // - I can validate the index, but not the value :( // - I can change the type of values, without affecting clients :) }; ``` Now to the questions: - Are there any other disadvantages of this approach that I'm failing to see? - Why do people prefer: - getter/setters methods with different names? - passing the value as a parameter? just for validating input or are there any other main reasons?

Original source