возвращаемое значение перегрузки оператора в C ++ - PullRequest
44 голосов
/ 25 февраля 2010

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

Например, при реализации операции + «строка + (строка)». как бы вы вернули возвращаемое значение, по ref или по val.

Ответы [ 5 ]

66 голосов
/ 25 февраля 2010

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

Например, 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, а затем выражение [result of cout << x ] << y. Поскольку оператор << on x возвращает ссылку на cout, выражение [result of cout << x ] << y эквивалентно cout << y, как и ожидалось.

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

12 голосов
/ 25 февраля 2010

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

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;
}
6 голосов
/ 25 февраля 2010

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

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

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

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

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

3 голосов
/ 25 февраля 2010

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

Впрочем, это скорее практическое правило. Вы можете разработать свой оператор в любом случае.

3 голосов
/ 25 февраля 2010

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

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

  • Если ваши объекты неизменны, вероятно, лучше вернуть по значению.
  • Если ваши объекты изменчивы, вероятно, лучше вернуться по ссылке.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...