Постоянная корректность при перегрузке оператора C ++ возвращает

StackOverflow https://stackoverflow.com/questions/1815903

Вопрос

Я немного сбит с толку относительно того, почему мне сказали возвращать 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= .Эмпирическое правило гласит: "Если это достаточно хорошо для целых чисел, то достаточно хорошо и для определяемых пользователем типов данных".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top