возвращаемое значение оператора, перегружающегося в C++

У меня есть вопрос о возвращаемом значении оператора, перегружающегося в C++. Обычно я нашел два случая, каждый - возврат значением, и каждый - возврат ссылкой. Таким образом, каково нижнее правило этого? Особенно в случае, когда можно использовать оператор непрерывно, такой как cout<<x<<y.

Например, когда реализация + операция "представляет в виде строки + (строка)". как Вы возвратили бы возвращаемое значение, касательно или val.

45
задан Tyler McHenry 25 February 2010 в 20:22
поделиться

5 ответов

Некоторые операторы возвращают значение по значению, некоторые - по ссылке. Как правило, оператор, результатом которого является новое значение (например, +, - и т. Д.), Должен возвращать новое значение по значению, а оператор, результатом которого является существующее значение, но измененное (например, <<, >>, + =, - = и т. д.) должны возвращать ссылку на измененное значение.

Например, cout - это std :: ostream , а вставка данных в поток - это операция изменения, поэтому для реализации оператора << для вставки в ostream оператор определяется следующим образом:

std::ostream& operator<< (std::ostream& lhs, const MyType& rhs)
{
  // Do whatever to put the contents of the rhs object into the lhs stream
  return lhs;
}

Таким образом, когда у вас есть составной оператор, такой как cout << x << y , подвыражение Сначала вычисляется cout << x , а затем вычисляется выражение [результат cout << x] << y . Поскольку оператор << on x возвращает ссылку на cout , выражение [результат cout << x] << y эквивалентно cout << y , как и ожидалось.

И наоборот, для «строка + строка» результатом является новая строка (обе исходные строки не изменяются), поэтому она должна возвращаться по значению (в противном случае вы бы вернули ссылку на временное, что является неопределенным поведением).

68
ответ дан 26 November 2019 в 21:09
поделиться

Если вы хотите, чтобы перегрузка вашего оператора вела себя как встроенный оператор, тогда правило довольно простое; стандарт точно определяет, как ведут себя встроенные операторы, и указывает, является ли результат встроенного rvalue или lvalue .

Правило, которое вы должны использовать:

  • если встроенный оператор возвращает rvalue , то ваша перегрузка должна возвращать ссылку
  • , если встроенный возвращает lvalue , то ваша перегрузка должна вернуть значение

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

Например, Kenny TM отметил в комментарии к другому ответу, что поток перегрузок для операторов << и >> возвращает ссылку на левый операнд, а это не то, как встроенные работают. Но разработчики потокового интерфейса сделали это, чтобы можно было связать потоки ввода-вывода.

7
ответ дан 26 November 2019 в 21:09
поделиться

В зависимости от оператора может потребоваться возврат по значению.

Однако, когда можно использовать и то, и другое, например, в operator + =, вы могли бы рассмотреть следующее:

  • Если ваши объекты неизменяемы, вероятно, лучше возвращаться по значению.
  • Если ваши объекты изменяемы, вероятно, лучше вернуться по ссылке.
3
ответ дан 26 November 2019 в 21:09
поделиться

Обычно вы возвращаетесь по ссылке в операции, которая изменяет значение того, над чем она работает, например = или + = . Все остальные операции возвращаются по значению.

Это скорее практическое правило. Вы можете сконструировать своего оператора в любом случае.

3
ответ дан 26 November 2019 в 21:09
поделиться

Чтобы попытаться ответить на ваш вопрос о строках, оператор + () для строк почти всегда реализуется как бесплатная (не являющаяся членом) функция, поэтому неявная преобразования могут выполняться по любому параметру. Таким образом, вы можете сказать что-то вроде:

string s1 = "bar";
string s2 = "foo" + s1;

Учитывая это, и мы видим, что ни один параметр не может быть изменен, он должен быть объявлен как:

RETURN_TYPE operator +( const string & a, const string & b );

Мы игнорируем RETURN_TYPE на данный момент. Поскольку мы не можем вернуть ни один параметр (потому что мы не можем их изменить), реализация должна создать новое сцепленное значение:

RETURN_TYPE operator +( const string & a, const string & b ) {
    string newval = a;
    newval += b;    // a common implementation
    return newval;
}

Теперь, если мы сделаем RETURN_TYPE ссылкой, мы вернем ссылку на локальный объект, который является хорошо известное «нет-нет», поскольку локальный объект не существует вне функции. Поэтому наш единственный выбор - вернуть значение, то есть копию:

string operator +( const string & a, const string & b ) {
    string newval = a;
    newval += b;    // a common implementation
    return newval;
}
13
ответ дан 26 November 2019 в 21:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: