Если возможно, в качестве функций, не являющихся и не являющихся друзьями.
Как описано Хербом Саттером и Скоттом Мейерсом, предпочитайте функции, не являющиеся друзьями, а не функции-члены, чтобы помочь увеличить инкапсуляцию.
В некоторых случаях, таких как потоки C ++, у вас не будет выбора, и вы должны использовать функции, не являющиеся членами.
Но, тем не менее, это не значит, что вы должны сделать эти функции друзьями своих классов: эти функции могут по-прежнему иметь доступ к вашему классу через средства доступа к ним. Если вам удастся написать эти функции таким образом, вы выиграете.
Об операторе << и >> прототипы
Я считаю, что примеры, которые вы привели в своем вопросе, неверны. Например;
ostream & operator<<(ostream &os) {
return os << paragraph;
}
Я даже не могу подумать, как этот метод может работать в потоке.
Вот два способа реализации операторов << и >>.
Допустим, вы хотите использовать потоковый объект типа T.
А что вы хотите извлечь / вставить из / в T соответствующих данных вашего объекта типа Paragraph.
Общие операторные << и >> прототипы функций
Первое существо как функции:
// T << Paragraph
T & operator << (T & p_oOutputStream, const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return p_oOutputStream ;
}
// T >> Paragraph
T & operator >> (T & p_oInputStream, const Paragraph & p_oParagraph)
{
// do the extraction of p_oParagraph
return p_oInputStream ;
}
Общий оператор << и >> прототипы метода
Второе существо как методы:
// T << Paragraph
T & T::operator << (const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return *this ;
}
// T >> Paragraph
T & T::operator >> (const Paragraph & p_oParagraph)
{
// do the extraction of p_oParagraph
return *this ;
}
Обратите внимание, что для использования этой нотации вы должны расширить объявление класса T. Для объектов STL это невозможно (вы не должны их изменять ...).
А что, если T - поток C ++?
Вот прототипы тех же операторов << и >> для потоков C ++.
Для базовых базовых_потоков и базовых_потоков
Обратите внимание, что это случай потоков, так как вы не можете изменить поток C ++, вы должны реализовать функции. Что означает что-то вроде:
// OUTPUT << Paragraph
template <typename charT, typename traits>
std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & p_oOutputStream, const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return p_oOutputStream ;
}
// INPUT >> Paragraph
template <typename charT, typename traits>
std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & p_oInputStream, const CMyObject & p_oParagraph)
{
// do the extract of p_oParagraph
return p_oInputStream ;
}
Для char istream и ostream
Следующий код будет работать только для потоков на основе символов.
// OUTPUT << A
std::ostream & operator << (std::ostream & p_oOutputStream, const Paragraph & p_oParagraph)
{
// do the insertion of p_oParagraph
return p_oOutputStream ;
}
// INPUT >> A
std::istream & operator >> (std::istream & p_oInputStream, const Paragraph & p_oParagraph)
{
// do the extract of p_oParagraph
return p_oInputStream ;
}
Рис Улерих прокомментировал тот факт, что код на основе символов является всего лишь «специализацией» общего кода над ним. Конечно, Рис прав: я не рекомендую использовать пример на основе символов. Это дано только здесь, потому что это проще для чтения. Поскольку это возможно только в том случае, если вы работаете только с потоками на основе символов, вам следует избегать этого на платформах, где распространен код wchar_t (то есть в Windows).
Надеюсь, это поможет.