Const-корректность в C ++ возвращает перегрузку оператора - PullRequest
4 голосов
/ 29 ноября 2009

Меня немного смущает, почему мне сказали возвращать const foo из бинарного оператора в c ++ вместо просто foo.

Я читал «Мышление в C ++» Брюса Экеля, и в главе о перегрузке операторов он говорит, что «делая возвращаемое значение [перегруженного двоичного оператора] const, вы утверждаете, что только const Функция-член может быть вызвана для этого возвращаемого значения. Это const-правильное решение, поскольку оно не позволяет хранить потенциально ценную информацию в объекте, который, скорее всего, будет утерян ».

Однако, если у меня есть оператор плюс, который возвращает 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, но это довольно громоздко, не так ли?

Спасибо!

Ответы [ 4 ]

4 голосов
/ 29 ноября 2009

Когда вы говорите ++ x, вы говорите «добавьте 1 к x, сохраните результат обратно в x и скажите мне, что это было». Это прединкрементный оператор. Но в ++ (a + b), как вы должны «сохранить результат обратно в a + b»?

Конечно, вы можете сохранить результат обратно во временную переменную, которая в настоящее время содержит результат a + b, который скоро исчезнет. Но если вам было все равно, где хранится результат, почему вы увеличиваете его, а не просто добавляете один?

4 голосов
/ 29 ноября 2009

FYI, ++(a + b) недопустимо даже с POD (обычные старые типы данных, такие как 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));
0 голосов
/ 10 декабря 2012

Я полагаю, что пример OP подойдет для вопроса, заменяется ли оператор сложения любым другим двоичным оператором, который возвращает ссылку, например, оператором присваивания:

Integer c( ++(a = b));

Я пришел сюда, задаваясь вопросом,должен заставить мой оператор присваивания возвращать постоянную или неконстантную ссылку. В некоторых руководствах используются неконстантные версии, в отличие от рекомендаций «Thinking in C ++».И некоторые другие ссылки обосновывают это:

Обратите внимание, что возвращенная ссылка не объявлена ​​как const.Это может немного сбивать с толку, потому что позволяет писать такие сумасшедшие вещи, как это:

MyClass a, b, c;

...

(а = б) = с;// Что ??

На первый взгляд, вы можете захотеть предотвратить подобные ситуации, используя operator = return const reference.Однако такие заявления будут работать с примитивными типами.И, что еще хуже, некоторые инструменты действительно полагаются на это поведение.Поэтому важно вернуть неконстантную ссылку от вашего оператора =.Практическое правило гласит: «Если этого достаточно для целочисленных значений, этого достаточно для определяемых пользователем типов данных».

0 голосов
/ 29 ноября 2009

Конструкторы копирования обычно берут ссылку const , решая эту проблему для вас.

(Наличие неконстантной копии ctor подразумевает некоторую передачу ресурсов, что иногда может быть полезно, но для 99% всех ситуаций это не требуется)

...