2010-03-16 8 views
5

Lorsque vous imprimez un objet, un opérateur ami < < est utilisé. Peut-on utiliser la fonction membre pour l'opérateur < <?Pourquoi la fonction ami est préférée à la fonction membre pour l'opérateur <<

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; 
} 

Un point est que la fonction ami nous permet de l'utiliser comme ceci

cout<<a<<b<<c 

Quelles autres raisons?

+3

Avez-vous vraiment besoin d'autres raisons? –

+0

@mmyers: J'essaie juste de comprendre aussi clairement que je peux .... – skydoor

+1

Il ne peut évidemment pas être une fonction de membre (voir la réponse de Charles Bailey), mais il ne doit pas être un * ami * - si vous pouvez l'implémenter en termes d'interface publique de la classe, ce serait super. – UncleBens

Répondre

11

Vous devez utiliser une fonction libre et non une fonction membre car pour les opérateurs binaires, le côté gauche est toujours *this pour les fonctions membres dont le côté droit est passé comme autre paramètre. Pour les opérateurs de flux de sortie, le côté gauche est toujours l'objet flux, donc si vous diffusez en flux vers une classe standard et que vous n'écrivez pas vous-même, vous devez fournir une fonction gratuite et non un membre de votre classe.

Bien qu'il soit possible de fournir un opérateur de flux vers l'arrière en fonction de membre et diffusez comme ceci:

myObject >> std::cout; 

-vous violer non seulement une convention de bibliothèque très forte, comme vous le soulignez, sortie enchaînant opérations ne fonctionnerait pas en raison du regroupement de gauche à droite de >>.

Edit: Comme d'autres l'ont noté, alors que vous devez en faire une fonction libre, il n'a besoin que d'être un friend si la fonction de diffusion en continu ne peut pas être mis en œuvre en termes de la classe interface publique.

10

Vous n'avez pas le choix - il doit s'agir d'une fonction gratuite.

Notez, cependant, qu'il ne doit pas nécessairement une fonction friend. Il suffit d'être un ami si vous avez réellement besoin de lui accorder un accès privé. Par exemple, j'utilise les éléments suivants dans les concours de programmation:

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

Pas besoin pour qu'il soit ami, first et second sont accessibles au public.

1

Autre raison dans votre exemple: il doit s'agir d'un friend car c'est la seule façon de définir une fonction libre dans la définition de classe. Si vous vouliez une fonction sans ami, il faudrait la définir en dehors de la classe.

Pourquoi préféreriez-vous définir dans la classe? Parfois, il est agréable de définir tous les opérateurs ainsi:

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 
}; 

pourrait être un peu plus convivial que:

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; 
} 

Cela suppose bien sûr que vous définissez les fonctions membres liées à la définition de classe , plutôt que de les déclarer là et de les définir dans un fichier .cpp.

Editer: J'ai utilisé + = et + comme exemple sans vraiment y penser, mais votre question concerne environ operator<<, qui n'a pas d'opérateurs étroitement liés comme operator+. Mais si operator<< appelle une ou plusieurs fonctions membres liées à l'impression, vous pouvez vouloir le définir près de l'endroit où elles sont définies.

0

Vous ne pouvez pas. Mais si vous ne voulez pas que ce soit une fonction d'ami, faites-en une fonction libre et mettez-la en œuvre en termes d'interface publique de la classe. Par exemple.

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

ostream& MyClass::print(ostream& os) 
{ 
    os << val; // for example. 
    return os; 
} 
Questions connexes