Постоянная корректность при перегрузке оператора C ++ возвращает
-
08-07-2019 - |
Вопрос
Я немного сбит с толку относительно того, почему мне сказали возвращать const foo из двоичного оператора в c ++ вместо просто foo.
Я читал книгу Брюса Эккеля "Мышление на C ++", и в главе о перегрузке операторов он говорит, что "делая возвращаемое значение [перегружающего двоичного оператора] const, вы заявляете, что для этого возвращаемого значения может быть вызвана только функция-член const.Это корректно, потому что это не позволяет вам хранить потенциально ценную информацию в объекте, который, скорее всего, будет утерян".
Однако, если у меня есть оператор plus, который возвращает const , и оператор увеличения префикса, этот код недопустим:
class Integer{
int i;
public:
Integer(int ii): i(ii){ }
Integer(Integer&);
const Integer operator+();
Integer operator++();
};
int main(){
Integer a(0);
Integer b(1);
Integer c( ++(a + b));
}
Чтобы разрешить такого рода присваивание, не имело бы смысла, чтобы оператор + возвращал неконстантное значение?Это можно было бы сделать, добавив const_casts , но это становится довольно громоздким, не так ли?
Спасибо!
Решение
Когда вы говорите ++ x, вы говорите "добавьте 1 к x, сохраните результат обратно в x и скажите мне, что это было".Это оператор предварительного увеличения.Но в ++ (a + b), как вы должны "сохранить результат обратно в a + b"?
Конечно, вы могли бы сохранить результат обратно во временное хранилище, которое в настоящее время содержит результат a + b, который достаточно скоро исчезнет.Но если вам действительно было все равно, где хранится результат, почему вы увеличили его вместо того, чтобы просто добавить один?
Другие советы
К ТВОЕМУ СВЕДЕНИЮ, ++(a + b)
является незаконным даже с PODs (простыми старыми типами данных, такими int
).Так что имеет смысл не разрешать это и для ваших собственных типов классов.Попробуй это:
int a = 1;
int b = 2;
int c = ++(a+b);
GCC возвращает error: lvalue required as increment operand
.
В вашем случае было бы предпочтительнее, чтобы ваш конструктор копирования принимал const Integer
аргументировать и создавать свои Integer c
вот так вместо этого:
Integer c(a + b + Integer(1));
Конструкторы копирования обычно принимают константа ссылка, решающая эту проблему за вас.
(Наличие неконстантного ctor копирования подразумевает некоторую передачу ресурсов, что иногда может быть полезно, но в 99% всех ситуаций это не требуется)
Я полагаю, что пример OP подошел бы к вопросу, заменяется ли оператор сложения любым другим двоичным оператором, который возвращает ссылку, например, оператором присваивания:
Integer c( ++(a = b));
Я пришел сюда, задаваясь вопросом, должен ли я заставить свой оператор присваивания возвращать постоянную или неконстантную ссылку. Некоторые учебные пособия используйте неконстантные версии, вопреки совету "Thinking in C ++".И некоторые другие ссылки приведите доводы, стоящие за этим:
Обратите внимание, что возвращаемая ссылка не объявлена const.Это может немного сбить с толку, потому что позволяет вам писать такие сумасшедшие вещи, как это:
Мой класс a, b, c;
...
(a = b) = c;// Что??
На первый взгляд, вы можете захотеть предотвратить подобные ситуации, заставив operator= возвращать ссылку const.Однако подобные инструкции будут работать с примитивными типами.И, что еще хуже, некоторые инструменты действительно полагаются на это поведение.Поэтому важно возвращать неконстантную ссылку из вашего operator= .Эмпирическое правило гласит: "Если это достаточно хорошо для целых чисел, то достаточно хорошо и для определяемых пользователем типов данных".