web-dev-qa-db-fra.com

Surcharge d'opérateur: fonction membre vs fonction non membre?

J'ai lu qu'un opérateur surchargé déclaré en tant que fonction membre est asymétrique car il ne peut avoir qu'un seul paramètre et l'autre paramètre passé automatiquement est le pointeur this. Il n’existe donc aucune norme permettant de les comparer. D'autre part, l'opérateur surchargé déclaré comme un friend est symétrique parce que nous passons deux arguments du même type et qu'ils peuvent donc être comparés.

Ma question est la suivante: quand je peux encore comparer la valeur d'un pointeur à une référence, pourquoi les amis sont-ils préférés? (utiliser une version asymétrique donne les mêmes résultats que symétrique) Pourquoi les algorithmes STL n'utilisent-ils que des versions symétriques?

105
badmaash

Si vous définissez votre fonction surchargée d'opérateur en tant que fonction membre, le compilateur traduit des expressions telles que s1 + s2 En s1.operator+(s2). Cela signifie que la fonction membre surchargée est appelée sur le premier opérande. C'est ainsi que fonctionnent les fonctions membres!

Mais que se passe-t-il si le premier opérande n'est pas une classe? Il y a un problème majeur si nous voulons surcharger un opérateur dont le premier opérande n'est pas un type de classe. Dites plutôt double. ne peut pas écrire comme ceci 10.0 + s2. Cependant, vous pouvez écrire une fonction membre surchargée d'opérateur pour des expressions telles que s1 + 10.0.

Pour résoudre ce problème ordering, nous définissons la fonction surchargée d’opérateur comme friend SI elle doit accéder à private membres. Faites-le friend UNIQUEMENT s'il doit accéder à des membres privés. Sinon, faites-le simplement non ami non-membre fonction pour améliorer encapsulation!

class Sample
{
 public:
    Sample operator + (const Sample& op2); //works with s1 + s2
    Sample operator + (double op2); //works with s1 + 10.0

   //Make it `friend` only when it needs to access private members. 
   //Otherwise simply make it **non-friend non-member** function.
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}

Lire ces:
n léger problème de classement en opérandes
Comment les fonctions non membres améliorent l'encapsulation

134
Nawaz

Ce n’est pas nécessairement une distinction entre les surcharges d’opérateurs friend et les surcharges d’opérateurs des fonctions membres, car il s’agit de la surcharge globale et des surcharges des opérateurs des fonctions membres.

Une raison de préférer une surcharge d'opérateur global est si vous souhaitez autoriser des expressions dont le type de classe apparaît du côté à droite d'un opérateur binaire. Par exemple:

Foo f = 100;
int x = 10;
cout << x + f;

Cela ne fonctionne que s'il existe une surcharge globale d'opérateur pour

Opérateur Foo + (int x, const Foo & f);

Notez que la surcharge globale de l'opérateur ne doit pas nécessairement être une fonction friend. Ceci n’est nécessaire que s’il a besoin d’accéder aux membres privés de Foo, mais ce n’est pas toujours le cas.

Quoi qu'il en soit, si Foo n'a eu qu'une surcharge d'opérateur de fonction membre, comme:

class Foo
{
  ...
  Foo operator + (int x);
  ...
};

... alors nous ne pourrions avoir que des expressions où une instance Foo apparaît sur l'opérateur à gauche de l'opérateur plus.

18
Charles Salvia