« ami » et fonctions << surcharge opérateur: Quelle est la bonne façon de surcharger un opérateur pour une classe?

StackOverflow https://stackoverflow.com/questions/2828280

Question

Dans un projet, je travaille sur, j'ai une classe Score, défini ci-dessous dans score.h. Je suis en train de surcharger ainsi, lors d'une opération de << est effectuée sur elle, _points + " " + _name est imprimé.

Voici ce que j'ai essayé de le faire:

ostream & Score::operator<< (ostream & os, Score right)
{
    os << right.getPoints() << " " << right.scoreGetName();
    return os;
}

Voici les erreurs renvoyées:

score.h(30) : error C2804: binary 'operator <<' has too many parameters

(Cette erreur apparaît 4 fois, en fait)

J'ai réussi à le faire fonctionner en déclarant la surcharge en fonction ami:

friend ostream & operator<< (ostream & os, Score right);

Et la suppression Score:: de la déclaration de la fonction score.cpp (effectivement ne pas déclarer comme membre).

Pourquoi ce travail, mais l'ancien morceau de code ne fonctionne pas?

Merci pour votre temps!

EDIT

J'ai supprimé toutes les mentions de la surcharge sur le fichier d'en-tête ... mais je reçois l'erreur suivante (et seulement). binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion) Pourquoi mon test, en main (), ne peut pas trouver la surcharge appropriée? (Ce n'est pas inclut, j'ai vérifié)

Ci-dessous la pleine score.h

#ifndef SCORE_H_
#define SCORE_H_

#include <string>
#include <iostream>
#include <iostream>

using std::string;
using std::ostream;

class Score
{

public:
    Score(string name);
    Score();
    virtual ~Score();
    void addPoints(int n);
    string scoreGetName() const;
    int getPoints() const;
    void scoreSetName(string name);
    bool operator>(const Score right) const;

private:
    string _name;
    int _points;

};
#endif
Était-ce utile?

La solution

Note: Vous pouvez regarder l'opérateur surcharge FAQ .


Les opérateurs binaires peuvent être soit des membres de leur classe d'argument à la main gauche ou fonctions libres. (Certains opérateurs, comme l'affectation, doivent être membres.) Étant donné que les opérateurs de flux de l'argument à la main gauche est un cours d'eau, les opérateurs de flux soit doivent être membres de la classe de flux ou fonctions libres. La façon canonique de mettre en œuvre operator<< pour tout type est le suivant:

std::ostream& operator<<(std::ostream& os, const T& obj)
{
   // stream obj's data into os
   return os;
}

Notez qu'il est pas une fonction membre. Notez également qu'il prend l'objet de flux par référence const. C'est parce que vous ne voulez pas copier l'objet afin de le diffuser et vous ne voulez pas que le streaming de le modifier soit.


Parfois, vous voulez diffuser des objets dont les internes ne sont pas accessibles par leur classe interface publique, de sorte que l'opérateur ne peut pas les atteindre. Ensuite, vous avez deux choix: soit placer un membre du public dans la classe qui fait le flux

class T {
  public:
    void stream_to(std::ostream&) const {os << obj.data_;}
  private:
    int data_;
};

et que l'appel de l'opérateur:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   obj.stream_to(os);
   return os;
}

ou faire l'opérateur un friend

class T {
  public:
    friend std::ostream& operator<<(std::ostream&, const T&);
  private:
    int data_;
};

afin de pouvoir accéder à des parties privées de la classe:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   os << obj.data_;
   return os;
}

Autres conseils

Disons que vous vouliez écrire une surcharge de l'opérateur pour + pour que vous puissiez ajouter deux objets Score à l'autre, et un autre pour que vous puissiez ajouter un int à un Score, et un troisième pour que vous puissiez ajouter un Score à un int. Ceux où Score est le premier paramètre peut être des fonctions membres de la partition. Mais celui où un int est le premier paramètre ne peut pas devenir fonctions membres de int, non? Pour vous aider, vous êtes autorisé à les écrire en tant que fonctions libres. C'est ce qui se passe avec cet opérateur de <<, vous ne pouvez pas ajouter une fonction de membre à ostream vous écrivez donc une fonction libre. C'est ce que cela signifie quand vous emportez la partie Score::.

Maintenant, pourquoi est-il d'être un friend? Il ne fonctionne pas. Vous êtes seulement appeler des méthodes publiques (getPoints et scoreGetName). Vous voyez beaucoup d'opérateurs d'amis parce qu'ils aiment parler directement aux variables privées. Il est ok par moi de le faire, parce qu'ils sont écrits et maintenus par la personne maintaing la classe. Il suffit de ne pas la partie ami embrouillé avec le membre-fonction-vs-fonction libre partie.

Vous obtenez des erreurs de compilation lorsque operator<< est une fonction membre dans l'exemple parce que vous créez un operator<< qui prend un Score comme premier paramètre (l'objet appelé de la méthode sur), puis en lui donnant un paramètre supplémentaire à la fin.

Lorsque vous appelez un opérateur binaire qui est déclaré en fonction de membre, le côté gauche de l'expression est l'objet appelé de la méthode sur. par exemple. pourrait de a + b fonctionne comme ceci:

A a;
B b

a.operator+(b)

Il est généralement préférable d'utiliser des opérateurs binaires non-membres (et dans certains cas - par exemple operator<<for ostream est la seule façon de le faire dans ce cas, le travail de puissance de a + b comme ceci:.

A a;
B b

operator+(a, b);

Voici un exemple complet deux façons de le faire; main () va afficher '55' à trois reprises:

#include <iostream>

struct B
{
    B(int b) : value(b) {}
    int value;
};


struct A
{
    A(int a) : value(a) {}
    int value;

    int operator+(const B& b) 
    {
        return this->value + b.value;
    }
};

int operator+(const A& a, const B& b)
{
    return a.value + b.value;
}

int main(int argc, char** argv)
{
    A a(22);
    B b(33);

    std::cout << a + b << std::endl;
    std::cout << operator+(a, b) << std::endl;
    std::cout << a.operator+(b) << std::endl;

    return 0;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top