Неконстантные геттеры?
Геттеры и сеттеры - это просто соглашение.Вместо того, чтобы предоставлять метод получения и установки, иногда используемая идиома состоит в том, чтобы предоставить что-то вроде
struct foo {
int val() const { return val_; }
int& val() { return val_; }
private:
int val_;
};
, чтобы в зависимости от константы экземпляра вы получали ссылку или копию:
void bar(const foo& a, foo& b) {
auto x = a.val(); // calls the const method returning an int
b.val() = x; // calls the non-const method returning an int&
};
Является ли это хорошим стилем в общем, вопрос мнения.Есть случаи, когда это вызывает путаницу, и другие случаи, когда это поведение именно то, что вы ожидаете (см. Ниже).
В любом случае, более важно разработать интерфейс класса в соответствии с тем, что классдолжен делать и как вы хотите его использовать, а не слепо следовать соглашениям о методах установки и получения (например, вы должны дать методу осмысленное имя, которое выражает то, что он делает, а не только с точки зрения «притворяться инкапсулированным», а теперь предоставьте мне«Доступ ко всем вашим внутренним объектам через геттеры», что на самом деле означает использование геттеров везде).
Конкретный пример
Учтите, что доступ к элементам в контейнерах обычно осуществляется следующим образом,В качестве игрушечного примера:
struct my_array {
int operator[](unsigned i) const { return data[i]; }
int& operator[](unsigned i) { return data[i]; }
private:
int data[10];
};
Контейнеры не скрывают элементы от пользователя (даже data
может быть общедоступным).Вы не хотите, чтобы различные методы обращались к элементам в зависимости от того, хотите ли вы прочитать или записать элемент, поэтому в данном случае вполне допустимо обеспечить const
и неконстантную перегрузку.
non-Const справка из получить против инкапсуляции
1029 * Maybe не так очевидно, но это немного спорно, поддерживают ли обеспечивающие добытчик и сеттера инкапсуляцию или наоборот.Хотя в целом этот вопрос в значительной степени основан на мнениях, для получателей, которые возвращают неконстантные ссылки, речь идет не столько о мнениях.Они нарушают инкапсуляцию.Рассмотрим
struct broken {
void set(int x) {
counter++;
val = x;
}
int& get() { return x; }
int get() const { return x; }
private:
int counter = 0;
int value = 0;
};
Этот класс не работает, как следует из названия.Клиенты могут просто получить ссылку, и у класса нет шансов подсчитать, сколько раз значение было изменено (как подсказывает set
).После того, как вы вернете неконстантную ссылку, в отношении инкапсуляции будет мало разницы в том, чтобы сделать член открытым.Следовательно, это используется только для случаев, когда такое поведение является естественным (например, контейнер).
PS
Обратите внимание, что ваш пример возвращает const T&
, а не значение,Это разумно для шаблонного кода, когда вы не знаете, сколько стоит копия, а для int
вы не получите много, возвращая const int&
вместо int
.Для ясности я использовал не шаблонные примеры, хотя для шаблонного кода вы, скорее всего, скорее вернете const T&
.