Я прочитал, что перегруженный оператор, объявленный как функция-член, асимметричен, поскольку он может иметь только один параметр, а другой параметр, передаваемый автоматически, - это указатель '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
появляется слева от оператора плюс.