Какие операторы должны быть объявлены друзьями? - PullRequest
30 голосов
/ 06 июня 2011

В некоторых книгах и часто в Интернете я вижу рекомендации типа "operator== должен быть объявлен как друг".

Как понять, когда оператор должен быть объявлен как друг, а когда он должен быть объявлен как член? Какие операторы чаще всего нужно объявлять друзьями, кроме == и <<?

Ответы [ 3 ]

39 голосов
/ 06 июня 2011

Это на самом деле зависит от того, будет ли класс находиться слева или справа от вызова operator== (или другого оператора). Если класс находится в правой части выражения и не обеспечивает неявное преобразование в тип, который можно сравнить с левой частью, вам нужно реализовать operator== как отдельную функцию или как friend класса. Если оператору требуется доступ к данным частного класса, он должен быть объявлен как friend.

Например,

* * 1010

позволяет сравнить сообщение со строкой

Message message("Test");
std::string msg("Test");
if (message == msg) {
    // do stuff...
}

но не наоборот

    if (msg == message) { // this won't compile

Вам нужно объявить друга operator== внутри класса

class Message {
    std::string content;
public:
    Message(const std::string& str);
    bool operator==(const std::string& rhs) const;
    friend bool operator==(const std::string& lhs, const Message& rhs);
};

или объявляют оператор неявного преобразования в соответствующий тип

class Message {
    std::string content;
public:
    Message(const std::string& str);
    bool operator==(const std::string& rhs) const;
    operator std::string() const;
};

или объявляют отдельную функцию, которой не нужно быть другом, если она не имеет доступа к данным частного класса

bool operator==(const std::string& lhs, const Message& rhs);
19 голосов
/ 06 июня 2011

Когда ваши операторы находятся за пределами класса, оба параметра могут участвовать в неявных преобразованиях типов (тогда как операторы, определяемые в теле класса, могут только правые операнды). Как правило, это является преимуществом для всех классических бинарных операторов (то есть ==, !=, +, -, <<, ...).

Конечно, вы должны объявлять операторы friend вашего класса только в том случае, если это необходимо, а не в том случае, если они вычисляют свой результат исключительно на основе открытых членов класса.

8 голосов
/ 06 июня 2011

Как правило, только операторы, которые реализованы в виде бесплатных функций, которым действительно необходим доступ к частным или защищенным данным класса, с которым они работают, должны быть объявлены как друзья, в противном случае они должны быть просто не-дружественными функциями, не являющимися членами.

Как правило, единственные операторы, которые я реализую как функции-члены, - это операторы, которые в основном асимметричны и в которых операнды не имеют эквивалентных ролей. В качестве членов я обычно использую те, которые должны быть членами: простое присваивание, (), [] и -> вместе с составными операторами присваивания, унарные операторы и, возможно, некоторые перегрузки << и >> для классов, которые сами являются потоковыми или потоковыми классами. Я никогда не перегружаю &&, || или ,.

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

Сохранение таких операторов, как !=, ==, <, +, / и т. Д., В качестве функций, не являющихся членами, позволяет идентично обрабатывать левый и правый операнды относительно последовательностей неявного преобразования, что помогает уменьшить количество удивительных асимметрий.

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