Каково различие между перегрузкой оператора с помощью friend
ключевое слово и как функция членства в классе?
Кроме того, каково различие в случае какой-либо перегрузки унарного оператора (т.е. как друг по сравнению с как функция членства)?
Джейкоб прав... friend
функция, объявленная внутри класса, имеет доступ к этому классу, но она вообще не внутри класса, и все остальные имеют к ней доступ.
Для перегрузки оператора, который не является членом класса (также называется свободная функция, она может быть другом, а может и нет), аргументы те же, что и операнды. Для той, которая является членом класса, первым операндом является "неявный аргумент", который становится this
.
Неявный аргумент отличается от первого аргумента свободной функции несколькими способами:
virtual
будет выбрана по динамическому типу первого операнда, что невозможно для свободных функций без дополнительного кода.)Ситуация одинакова для унарных, бинарных или n-арных (в случае operator()
).
Привилегия членов мутации: Операторы, изменяющие первый операнд (например, +=
, =
, префикс ++
) должны быть реализованы как функции-члены, и должны реализовывать исключительно потроха всех перегрузок. Постфикс ++
- гражданин второго сорта; он реализуется как Obj ret = *this; ++ this; return ret;
. Заметим, что это иногда распространяется на копирующие конструкторы, которые могут содержать *this = initializer
.
Правило свободы для коммутаторов: Только коммутативные операторы (например, /
) должны быть свободными функциями; все остальные операторы (например, унарное что угодно) должны быть членами. Коммутативные операторы по своей природе создают копию объекта; они реализуются как Obj ret = lhs; ret @= rhs; return ret;
где @
- коммутативный оператор, а lhs
и rhs
- аргументы левой и правой сторон, соответственно.
Золотое правило дружбы в C++: Избегайте дружбы. friend
загрязняет семантику конструкции. Следствие перегрузки: Перегрузка проста, если вы следуете вышеприведенным правилам, тогда friend
безвреден. friend
включение шаблонных определений перегрузки позволяет поместить их внутрь class {
скобок.
Обратите внимание, что некоторые операторы не могут быть свободными функциями: =
, ->
, []
, и ()
, потому что стандарт специально говорит об этом в разделе 13.5. Думаю, это все... Я думал, что унарные &
и *
тоже, но, видимо, я ошибался. Однако их следует всегда перегружать как члены, и только после тщательного обдумывания!
Функция-член требует, чтобы левый оператор был этого типа. Функция друга может разрешить неявное приведение к левому оператору .
Так, например, мы создаем класс BigInt. И мы создаем оператор функции-члена +, чтобы взять правый оператор BigInt.
Теперь допустим, что у BigInt есть конструктор, который принимает обычный тип int. Этот конструктор НЕ является явным (явное ключевое слово) и принимает один параметр. Это означает, что C ++ может неявно преобразовывать int в BigInt.
Когда у нас есть эти вещи, мы можем сделать это:
BigInt foo (5); BigInt bar; bar = foo + 5;
Но мы НЕ МОЖЕМ сделать это:
BigInt foo (5) BigInt bar; bar = 5 + foo;
Однако, если мы использовали функцию друга вместо функции-члена, тогда обе будут работать.
Функции-члены могут вызываться для rvalue, тогда как свободные функции, принимающие ссылки на неконстантные, не могут быть вызваны с rvalue. Например, ++ function_returning_iterator_by_value ()
компилируется, только если вы реализуете operator ++
как член.
Разница в том, что функция friended фактически находится в глобальной области видимости, поэтому вам не нужно быть экземпляром класса, чтобы иметь к ней доступ.