Почему дружественная функция предпочтительнее функции-члена для оператора << - PullRequest
5 голосов
/ 17 марта 2010

Когда вы собираетесь распечатать объект, используется оператор Friend <<. Можем ли мы использовать функцию-член для оператора <<? </p>

class A {

public:
void operator<<(ostream& i) { i<<"Member function";}
friend ostream& operator<<(ostream& i, A& a) { i<<"operator<<"; return i;}
};


int main () {

   A a;
   A b;
   A c;
   cout<<a<<b<<c<<endl;
   a<<cout;
  return 0;
}

Одно замечание - функция друга позволяет нам использовать ее вот так

cout<<a<<b<<c

Какие еще причины?

Ответы [ 4 ]

11 голосов
/ 17 марта 2010

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

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

Хотя было бы возможно предоставить оператор обратного потока в качестве функции-члена и выполнить потоковую передачу следующим образом:

myObject >> std::cout;

вы не только нарушите очень строгое библиотечное соглашение, как вы указали, цепочка операций вывода не будет работать из-за группировки слева направо >>.

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

10 голосов
/ 17 марта 2010

У вас нет выбора - это должна быть бесплатная функция.

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

template <class A, class B>
std::ostream& operator<<(std::ostream& os, const std::pair<A, B>& p)
{
  return os << '(' << p.first << ", " << p.second << ')';
}

Нет необходимости дружить, поскольку first и second доступны публично.

1 голос
/ 17 марта 2010

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

Почему вы предпочитаете определять это в классе? Иногда полезно определить все операторы вместе:

struct SomeClass {
    // blah blah blah
    SomeClass &operator+=(const SomeClass &rhs) {
        // do something
    }
    friend SomeClass operator+(SomeClass lhs, const SomeClass &rhs) {
        lhs += rhs;
        return lhs;
    }
    // blah blah blah
    // several pages later
};

может быть немного более удобным, чем:

struct SomeClass {
    // blah blah blah
    SomeClass &operator+=(const SomeClass &rhs) {
        // do something
    }
    // blah blah blah
    // several pages later
};

SomeClass operator+(SomeClass lhs, const SomeClass &rhs) {
    lhs += rhs;
    return lhs;
}

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

Редактировать: я использовал + = и + в качестве примера, не задумываясь об этом, но ваш вопрос касается operator<<, который не имеет тесно связанных операторов, как operator+. Но если operator<< вызывает одну или несколько функций-членов, связанных с печатью, вы можете определить ее рядом с тем местом, где они определены.

0 голосов
/ 17 марта 2010

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

 ostream& operator<<(ostream& os, Myclass& obj)
{
   return obj.print(os);
}

ostream& MyClass::print(ostream& os)
{
   os << val; // for example.
   return os;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...