Когда Вы собираетесь распечатать объект, друг, оператор <<используется. Мы можем использовать функцию членства для оператора <<?
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
Что другие причины?
Вы должны использовать свободную функцию, а не функцию-член, так как для бинарных операторов левая часть всегда *this
для функций-членов, а правая часть передается как другой параметр.
Для операторов выходного потока левая часть всегда является объектом потока, поэтому если вы передаете поток в стандартный класс, а не пишете поток сами, то вам придется предоставить свободную функцию, а не член вашего класса.
Хотя можно было бы предоставить оператор обратного потока как функцию-член и передавать поток вот так:
myObject >> std::cout;
мало того, что вы нарушите очень сильное библиотечное соглашение, как вы указали, цепочка операций вывода не будет работать из-за группировки слева направо >>
.
Edit: Как отметили другие, хотя вы должны сделать ее свободной функцией, она должна быть только другом
, если потоковая функция не может быть реализована в терминах публичного интерфейса класса.
У вас нет выбора - это должна быть свободная функция.
Заметьте, однако, что это не обязательно должна быть дружественная
функция. Она должна быть другом только в том случае, если вам действительно нужно предоставить ей частный доступ. Например, на соревнованиях по программированию я использую следующее:
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
доступны публично.
Вы не можете. Но если вы не хотите, чтобы это была функция friend, сделайте ее свободной функцией и реализуйте ее в терминах публичного интерфейса класса. Например,
ostream& operator<<(ostream& os, Myclass& obj)
{
return obj.print(os);
}
ostream& MyClass::print(ostream& os)
{
os << val; // for example.
return os;
}
Еще одна причина в вашем примере - это должен быть друг
, потому что это единственный способ определить свободную функцию внутри определения класса. Если вам нужна функция без друзей, она должна быть определена вне класса.
Почему вы предпочитаете определять его в классе? Иногда приятно определять все операторы вместе:
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 <<
вызывает одну или несколько функций-членов, связанных с печатью, вы можете захотеть определить ее рядом с тем местом, где они определены.