Все дело в том, что внешняя
перегрузка операторов должна соблюдать правила
ADL.
Перегрузка оператора в виде внешней функции является частью внешнего интерфейса того типа, для которого оператор перегружается. В случае бинарных операций перегрузка производится для типа левого операнда.
Твой
operator<<(ofstream&, const Book&)
должен быть определен в пространстве имен
std
, т.к.
ofstream
определен именно в этом пространстве.
Правильная перегрузка должна выглядеть так:
namespace std
{
// use the `Book` type definitely from global namespace.
ofstream& operator<<(ofstream &of, const ::Book &book)
{
// ...
}
}
И еще вопрос: что нужно возвращать из этой функции?
Конкретно
этот оператор (в терминологии стандартных стримов) возвращает левый операнд по ссылке.