Это вопрос новичка в C ++. Я читал статью «Функциональный объект» в Википедии. В статье есть пример на C ++, подобный следующему:
struct printClass {
int &count;
printClass(int &n) : count(n) {}
void operator()(int &i) const {
count++;
cout << i << "[" << count << "] ";
}
};
int main(int argc, char** argv) {
vector<int> a(5, 7);
a[4] = -1;
a.resize(10, 3);
int state = 0;
for_each(a.rbegin(), a.rend(), printClass(state));
}
У меня есть 2 вопроса:
Почему он не компилируется, когда count является обычной переменной, а не ссылочным типом? демонстрация
Почему он не компилируется, я изменяю ctor
к следующему? демонстрация
printClass(int &n) { count = n; }
Благодарю.
РЕДАКТИРОВАТЬ: Спасибо за объяснение. Я вижу, что следующая версия тоже работает. Есть ли причина для выбора одного над другим?
struct printClass {
int count;
printClass(int n) { count = n; }
void operator()(int &i) {
count++;
cout << i << "[" << count << "] ";
}
};
РЕДАКТИРОВАТЬ: На основании ответа iammilind, вот третья версия, которая работает тоже с использованием const_cast<int &>
,
struct printClass {
int count ;
printClass(int n) : count(n) {}
void operator()(int &i) const {
const_cast<int &>(count)++;
cout << i << "[" << count << "] ";
}
};
(1) Почему он не компилируется, когда count является обычной переменной, а не
ссылочный тип?
Это очень интересный вопрос. Вопрос должен быть скорее, почему код компилируется, когда count
объявлен в качестве ссылки. 🙂
Обычная переменная не работает, потому что int count
не может быть изменено внутри const
квалифицированная функция operator()(int &i) const;
,
Рекомендации немного отличаются. В вашем коде вы объявляете метод как const
, Который означает, что count
что относится к i
Теперь не может ссылаться на что-либо еще.
Но это все равно невозможно из-за характера ссылок :). Нельзя изменить привязку ссылки после инициализации.
operator()
просто проверяет, меняете ли вы привязку count
к чему-то еще или нет? И ответ всегда — нет. Так как count++
изменяет значение, указанное count
а не обязательный.
В вашем коде не имеет значения, является ли метод-член const
или нет, когда дело доходит до int& count
,
Относиться int& count;
в int* const p_count;
и попробуйте смоделировать ситуацию самостоятельно.
(2) Почему он не компилируется, я меняю ctor на следующий?
CountFrom(int &n) { count = n; }
Потому что ссылка должна быть присвоена переменной при инициализации. В простом примере;
int i, &r; // error, because 'r' not initialized
r = i; // this is not initialization but a copy
Кстати, вы должны быть особенно осторожны, когда имеете дело со ссылочными переменными внутри class
, Потому что это легко испортить их масштабы и обоснованность.
Например, здесь действительность count
зависит от объема i
,
редактировать: После вашего второго редактирования очень просто знать, почему эта версия работает.
Так как count
теперь простая переменная. Его можно пропустить из инициализации в списке инициализатора конструктора в отличие от ссылки.
Кроме того const
правильность operator()
ушел, поэтому любая переменная-член class
теперь можно изменить внутри него.
Вы должны выбрать const
версия метода-члена, если вы хотите заявить, что нет class
член «должен» измениться внутри него (если не mutable
или вы используете const_cast
). Во всех остальных случаях используйте обычную версию метода member. Они оба могут сосуществовать в зависимости от вашей бизнес-логики. Это довольно широкий вопрос, и для этого стоит иметь другую ветку.
Других решений пока нет …