Открытые переменные плохой практики против функций Getters и Setters?

Я наткнулся на это во время его потока, и это торчало для меня, как больной палец с тех пор. Я подумал, может быть, если бы я сохранил видео и вернусь к нему в будущем, когда буду более опытным, я пойму это, но он просто продолжал беспокоиться, чтобы просто оставить его. Здесь видео...

Он автоматически запускается в 1:13:00 для вас.

https://youtu.be/uHSLHvWFkto?t=4380

Как новый программист на C/С++, услышав это, он полностью исказил мой образ мышления. С ним, будучи профессионалом, и все, что я должен взять на себя, но мне нужна определенная ясность. Из сайтов, видеороликов, книг я читал, что использование общедоступных переменных - это плохая практика, но из того, что я получаю от этого видео, говорилось иначе. В видео он использует структуру, которая по умолчанию имеет модификатор доступа "public" и класс, который имеет доступ по умолчанию к "private". Что-то я здесь не понимаю.

Я не знаю, что делать. Если я сделаю свои переменные общедоступными, я не буду рисковать двусмысленностью? То, как он говорит, что он будет автоматически запускать кого-то для кодирования в формате, доходит до меня, ха-ха! Какой из них я должен использовать? Когда и почему?

Ответ 1

Прежде всего, struct полностью эквивалентен class, но с доступом к члену по умолчанию public, а не private.

Теперь, в объектно-ориентированном программировании (ООП), не считается хорошей практикой иметь члены данных public (переменные), поскольку это делает весь ваш код зависимым от внутренних элементов class и, таким образом, нарушает изначальную принцип ООП, и это...

Священная и священная инкапсуляция

Инкапсуляция - это философия кодирования, в которой говорится, что класс должен обладать как данными, так и кодом, который управляет им в одном ограниченном объекте. То есть вы не обращаетесь к директиве данных, а используете методы из class для управления такими данными. Это имеет несколько преимуществ дизайна, например, что вы будете знать, что никакой код, кроме одного внутри класса, не может включать ошибки в отношении манипулирования такой информацией.

Теперь get() ers и set() ers, иначе известные как accessors, полная ложь! С аксессуарами вы обманываете себя, думая, что вы уважаете инкапсуляцию, когда вы скорее ломаете! Он добавляет раздувание, ненужную многословие, ошибки и все, кроме инкапсуляции. Вместо class Person с unsigned getAge() и void setAge(unsigned) используйте его с unsigned getAge() и a void incrementAge() или, тем не менее, хотите его называть.

Теперь, на ваш вопрос ядро ​​...

"Обычные старые" структуры

Инкапсуляция не всегда желательна. Хотя вы должны (обычно) не делать это в файлах заголовков (опять же, по крайней мере, для некоторого количества инкапсуляции), вы можете создать статический простой старый struct, который является приватным для отдельной единицы перевода. Моя рекомендация - сделать их даже "старше", чем они есть, т.е....

  • Все элементы данных public.
  • Нет методов.
  • Нет конструкторов (кроме неявных).
  • Наследование всегда является общедоступным и разрешено только с других простых старых struct s.
  • Повторяю, не помещать их в файлы заголовков!

Теперь другое использование для простого старого struct (по иронии) метапрограмматического экспорта данных и типов constexpr, иначе известного как метапрограммирование современных-hardcore-template-without-have-to-type- public везде, например...

template<bool B, typename T>
struct EnableIf {};

template<typename T>
struct EnableIf<true, T> {
    typedef T type;
};

template<bool B, typename T>
using SFINAE = typename EnableIf<B, T>::Type;

Ответ 2

По моему опыту люди используют геттеры/сеттеры чрезмерно без уважительной причины.

Можно подумать о двух основных типах классов: о группировании связанных данных и о других, обеспечивающих поведение.

Классы поведения должны быть инкапсулированы без публичных элементов данных.

В классах данных обычно должны присутствовать члены данных и поведение.

Серая область между этими двумя является изменчивыми классами данных с инвариантами или зависимостями между членами, например. если член a равен 1, член b должен находиться в диапазоне [1-10]. Для таких случаев использование геттеров/сеттеров может быть оправдано. Для неизменяемых классов данных конструктор должен установить инвариант.

Ответ 3

Конечно, трудно контролировать внутреннюю согласованность вашего объекта, если вы публикуете публичные члены данных.

Что хорошо работает, так это использовать конструкторы для настройки состояния объекта, а затем использовать общедоступные функции для извлечения значений переменных-членов, но только если это необходимо. Если вам нужно мутировать объект после построения, тогда предоставьте очень конкретные методы для этой цели.

Если, однако, ваш объект является чем-то большим, чем то, что агрегирует ортогональные типы данных, тогда используйте открытый доступ для всех членов: a struct хорошо работает для этого.

Обратите внимание, что единственное различие между struct и a class заключается в том, что в первом случае доступ по умолчанию public, тогда как в последнем он private.

Ответ 4

Если вы сохраняете свои данные членами private, вы можете легко контролировать доступ к их значению. Например, в вашем коде есть переменная age.

public:
int age;

Теперь кто-то вне вашего класса может легко изменить значение возраста, может также назначить недопустимое значение, например age = -10. Но ваша логика предполагает, что возраст не может быть отрицательным, поэтому наилучшей практикой является сохранение переменной private и предоставление некоторой функции, которая присваивает значение вашей переменной.

private:
int age;

public:
void setAge(int age)
{
 if (age > 0)
   this->age = age;

}