Перегрузка оператора: функция-член или функция, не являющаяся членом?

Я прочитал, что перегруженный оператор, объявленный как функция-член, асимметричен, поскольку он может иметь только один параметр, а другой параметр, передаваемый автоматически, - это указатель 'this'. Поэтому нет никакого стандарта для их сравнения. С другой стороны, перегруженный оператор, объявленный как друг, симметричен, потому что мы передаем два аргумента одного типа и, следовательно, их можно сравнить. Мой вопрос в том, что, когда я все еще могу сравнить указатель lvalue с ссылкой, почему друзья предпочитают? (использование асимметричной версии дает те же результаты, что и симметричные) Почему алгоритмы STL используют только симметричные версии?

Ответ 1

Если вы определяете свою перегруженную функцию в качестве функции-члена, тогда компилятор переводит выражения типа s1 + s2 в s1.operator+(s2). Это означает, что оператор-перегруженная функция-член вызывается в первом операнде. Вот как работают функции-члены!

Но что, если первый операнд не является классом? Есть серьезная проблема, если мы хотим перегрузить оператор, где первый операнд не является типом класса, а скорее скажем double.. Таким образом, вы не можете писать так 10.0 + s2. Тем не менее, вы можете записать оператор-перегруженную функцию-член для выражений типа s1 + 10.0.

Чтобы решить эту задачу упорядочения, мы определяем операторную перегруженную функцию как friend ЕСЛИ ей необходимо получить доступ к элементам private. Сделать его friend ТОЛЬКО, когда ему нужно получить доступ к закрытым членам. В противном случае просто создайте функцию non-friend non-member для улучшения инкапсуляции!

class Sample
{
 public:
    Sample operator + (const Sample& op2); //works with s1 + s2
    Sample operator + (double op2); //works with s1 + 10.0

   //Make it `friend` only when it needs to access private members. 
   //Otherwise simply make it **non-friend non-member** function.
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}

Прочтите эти данные: Небольшая проблема упорядочения в операндах
Как не членские функции улучшают инкапсуляцию

Ответ 2

Это не обязательно различие между перегрузками операторов friend и перегрузками операторов функций-членов, так как это происходит между глобальными перегрузками операторов и перегрузками оператора функции члена.

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

Foo f = 100;
int x = 10;
cout << x + f;

Это работает только при наличии глобальной перегрузки оператора для

Оператор Foo + (int x, const Foo & f);

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

Несмотря на это, если Foo имел только перегрузку оператора функции-члена, например:

class Foo
{
  ...
  Foo operator + (int x);
  ...
};

... тогда мы могли бы иметь только выражения, в которых экземпляр Foo появляется слева от оператора плюс.