I think the reason the C ++ community frowns on getters and setters is because C ++ offers much better alternatives. For example:
template <class T> class DefaultPredicate { public: static bool CheckSetter (T value) { return true; } static void CheckGetter (T value) { } }; template <class T, class Predicate = DefaultPredicate <T>> class Property { public: operator T () { Predicate::CheckGetter (m_storage); return m_storage; } Property <T, Predicate> &operator = (T rhs) { if (Predicate::CheckSetter (rhs)) { m_storage = rhs; } return *this; } private: T m_storage; };
which can then be used as follows:
class Test { public: Property <int> TestData; Property <int> MoreTestData; }; int main () { Test test; test.TestData = 42; test.MoreTestData = 24; int value = test.TestData; bool check = test.TestData == test.MoreTestData; }
Note that I added the predicate parameter to the property class. At the same time, we can get a creative, for example, property for storing the integer value of the color channel:
class NoErrorHandler { public: static void SignalError (const char *const error) { } }; class LogError { public: static void SignalError (const char *const error) { std::cout << error << std::endl; } }; class Exception { public: Exception (const char *const message) : m_message (message) { } operator const char *const () { return m_message; } private: const char *const m_message; }; class ThrowError { public: static void SignalError (const char *const error) { throw new Exception (error); } }; template <class ErrorHandler = NoErrorHandler> class RGBValuePredicate : public DefaultPredicate <int> { public: static bool CheckSetter (int rhs) { bool setter_ok = true; if (rhs < 0 || rhs > 255) { ErrorHandler::SignalError ("RGB value out of range."); setter_ok = false; } return setter_ok; } };
and it can be used as follows:
class Test { public: Property <int, RGBValuePredicate <> > RGBValue1; Property <int, RGBValuePredicate <LogError> > RGBValue2; Property <int, RGBValuePredicate <ThrowError> > RGBValue3; }; int main () { Test test; try { test.RGBValue1 = 4; test.RGBValue2 = 5; test.RGBValue3 = 6; test.RGBValue1 = 400; test.RGBValue2 = 500; test.RGBValue3 = -6; } catch (Exception *error) { std::cout << "Exception: " << *error << std::endl; } }
Note that I also handled the wrong values with the template parameter.
Using this as a starting point, it can be expanded in many ways.
For example, suppose the property store is different from the public value type - therefore, the RGBValue above can use unsigned char for storage, but the interface is int.
Another example is to modify a predicate so that it can change the value of setter. In the RGBValue above, this can be used to fix values in the range 0 to 255, and not to generate errors.