Перегрузка оператора: функция-член или функция-не-член? - PullRequest
105 голосов
/ 07 января 2011

Я прочитал, что перегруженный оператор, объявленный как функция-член, является асимметричным , поскольку он может иметь только один параметр, а другой передаваемый параметр автоматически является указателем this.Таким образом, не существует стандарта для их сравнения.С другой стороны, перегруженный оператор, объявленный как friend, является симметричным , поскольку мы передаем два аргумента одного типа и, следовательно, их можно сравнивать.

Мой вопрос заключается в том, что когда явсе еще можно сравнить lvalue указателя со ссылкой, почему друзья предпочитают?(использование асимметричной версии дает те же результаты, что и симметричное). Почему в алгоритмах STL используются только симметричные версии?

Ответы [ 2 ]

133 голосов
/ 07 января 2011

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

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

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

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
}

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

18 голосов
/ 07 января 2011

Это не обязательно различие между 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 появляется в слева оператора плюс.

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