Почему люди пишут получатели частного поля, возвращающие неконстантную ссылку?
Мы все можем согласиться с тем, что общедоступные переменные являются плохими для инкапсуляции и всего этого. Тем не менее, я заметил много кода, который делает этот тип материала:
class foo {
private:
int integer_;
string someString_;
// other variables
public:
int& integer() { return integer_; }
string& someString() { return someString_; }
// other "functions"
}
int main() {
foo f;
f.integer() = 10;
f.someString() = "something";
return 0;
}
Я видел, что это используется во многих местах, и я не понимаю почему. В основном он возвращает ссылку на данные и, таким образом, выставляет ее непосредственно снаружи. Таким образом, инкапсуляция на самом деле не достигается, а не с любой точки зрения.
Почему это обычно используется?
Ответы
Ответ 1
Там повторяющаяся мантра, что функции getter/setter должны использоваться для инкапсуляции ваших данных. Поэтому многие (неопытные или перегруженные кофе) программисты получают идею, что они должны использовать что-то вроде:
int& integer() { return integer_; }
но это не сильно отличается от простого написания:
class foo {
public: // <<<
int integer_;
string someString_;
// ...
};
Ну, он добавляет вызов функции, но вы не можете контролировать то, что делает клиент со ссылкой.
Если вы действительно хотите предоставить функцию getter, напишите:
const int& integer() const { return integer_; }
Соответствующая функция сеттера выглядит следующим образом:
void integer(const int& value) {
integer_ = value;
}
Ответ 2
Я должен частично не согласиться с ответами @πάνταῥεῖ и @Rakete1111, учитывая, как определение класса является тем, что может развиваться со временем.
Хотя верно, что часто эти методы getter написаны кем-то, кто только что услышал мантру "без разоблачения", они также могут иметь законное использование:
- Метод getter позже может быть изменен, чтобы включить какую-либо проверку достоверности или код выделения ресурсов, прежде чем возвращать ссылку, - прямой доступ к элементу данных не позволяет. Хотя это означает изменение кода класса, это не требует изменения кода пользователя класса. Кроме того, если реализация геттера не отображается в заголовке класса, возможно, даже не потребуется перекомпилировать код пользователя класса. Примечание. Выполнение этого, вероятно, является признаком другого плохого выбора дизайна.
- Метод getter может быть переопределен подклассом (в этом случае он часто делается виртуальным методом) аналогично выше.
- Метод getter позже может заменить возвращаемый тип proxy для исходного типа элемента данных, а не ссылкой на фактический член, который больше не может существовать. Подумайте, как работает
vector<bool>
; когда вы вызываете его operator[]
, вы не получаете boolean&
, вы получаете какой-то прокси-сервер, который при назначении или назначении выполняет соответствующее извлечение или настройку бит.
- IIANM, геттер не может использоваться для не-const-экземпляров. Таким образом, на самом деле это ограничивает доступ к тому, чтобы разоблачить участника. Независимо от того, действительно ли автор класса имел в виду, что это другой вопрос...
Подводя итог: Получатель "dummy" не-const-reference может быть заглушкой для другого, значимого кода.
Это, как говорится, часто является хорошей идеей просто заставить геттер вернуть ссылку на константу или значение. Или просто выставлять поле в тех случаях, когда оно подходит (и некоторые из них тоже).
Ответ 3
Я бы решительно отказался возвращать ссылку на частную переменную. Не потому, что он разрушает инкапсуляцию, а потому, что это не нужно: почему бы не сделать переменную public
в первую очередь?
Нарушение инкапсуляции плохо, да, но это не означает, что каждая переменная должна быть private
. Некоторые переменные предназначены для чтения и изменения от пользователя, поэтому имеет смысл сделать их public
. Например, возьмите std::pair
, он имеет две переменные public member, first
и second
. Это неплохая практика.
Единственный раз, когда это не имеет смысла, это когда переменная не должна быть записана. Это было бы плохо, так как это фактически нарушит инкапсуляцию и сделает всю программу сложной для отладки.
Ответ 4
Эта конструкция может использоваться для целей отладки.
Если у вас есть общедоступная переменная, вы не можете легко контролировать ее использование.
Преобразование его в пару частных переменных и возвращающих метод ссылок позволит вам установить точку останова и/или записать вызовы.
Однако раздельный getter и setter будут работать с той же целью еще лучше, поэтому это просто преимущество перед обычными переменными public.
Ответ 5
Я написал это один раз. Я планировал позже вернуться и заменить полевого получателя чем-то, что вернуло объект стека к чему-то, что можно было бы придать оригинальному типу и присвоить оригинальному типу. Это позволило мне вернуться позже и перехватить все назначения, чтобы включить проверки.
Своего одержимого техником. Ни один из других кодеров в проекте не мог понять это вообще. Весь стек был вырван.