Si possible, en tant que fonctions non-membres et non-amis.
Comme décrit par Herb Sutter et Scott Meyers, préférez les fonctions non-membres non-amis aux fonctions membres, pour aider à augmenter l'encapsulation.
Dans certains cas, comme les flux C ++, vous n'aurez pas le choix et devez utiliser des fonctions non membres.
Mais encore, cela ne signifie pas que vous devez rendre ces fonctions amis de vos classes: ces fonctions peuvent toujours accéder à votre classe via vos accesseurs de classe. Si vous réussissez à écrire ces fonctions de cette façon, vous avez gagné.
À propos des prototypes d'opérateur << et >>
Je pense que les exemples que vous avez donnés dans votre question sont faux. Par exemple;
ostream & operator<<(ostream &os) {
return os << paragraph;
}
Je ne peux même pas commencer à penser comment cette méthode pourrait fonctionner dans un flux.
Voici les deux manières d'implémenter les opérateurs << et >>.
Supposons que vous souhaitiez utiliser un objet semblable à un flux de type T.
Et que vous souhaitez extraire / insérer de / dans T les données pertinentes de votre objet de type Paragraphe.
Prototypes de fonctions d'opérateurs génériques << et >>
Le premier étant en tant que fonctions:
// 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 ;
}
Prototypes de méthodes d'opérateurs génériques << et >>
Le second étant comme méthodes:
// 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 ;
}
Notez que pour utiliser cette notation, vous devez étendre la déclaration de classe de T. Pour les objets STL, ce n'est pas possible (vous n'êtes pas censé les modifier ...).
Et si T est un flux C ++?
Voici les prototypes des mêmes opérateurs << et >> pour les flux C ++.
Pour basic_istream et basic_ostream génériques
Notez que c'est le cas des flux, comme vous ne pouvez pas modifier le flux C ++, vous devez implémenter les fonctions. Ce qui veut dire quelque chose comme:
// 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 ;
}
Pour char istream et ostream
Le code suivant fonctionnera uniquement pour les flux basés sur des caractères.
// 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 ;
}
Rhys Ulerich a commenté le fait que le code à base de caractères n'est qu'une "spécialisation" du code générique au-dessus. Bien sûr, Rhys a raison: je ne recommande pas l'utilisation de l'exemple basé sur char. Il n'est donné ici que parce qu'il est plus simple à lire. Comme il n'est viable que si vous travaillez uniquement avec des flux basés sur char, vous devez l'éviter sur les plates-formes où le code wchar_t est courant (c'est-à-dire sous Windows).
J'espère que cela aidera.