2010-05-13 3 views
18

Dans un projet sur lequel je travaille, j'ai une classe Score, définie ci-dessous dans score.h. J'essaye de le surcharger ainsi, quand une opération << est exécutée là-dessus, _points + " " + _name est imprimé.fonctions 'friend' et << surcharge de l'opérateur: Quelle est la bonne façon de surcharger un opérateur pour une classe?

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 comme une fonction d'ami:

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

Et en supprimant le Score:: de la déclaration de fonction dans score.cpp (en fait ne pas le déclarer en tant que membre).

Pourquoi cela fonctionne-t-il, mais pas l'ancien morceau de code?

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) Comment se fait-il que mon test, dans main(), ne trouve pas la surcharge appropriée? (Ce ne sont pas les comprend, j'ai vérifié)

est inférieure à la score.h pleine

#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 

Répondre

54

Note: Vous pouvez regarder le operator overloading FAQ.


Les opérateurs binaires peuvent être des membres de la classe ou des fonctions libres de leur argument de gauche. (Certains opérateurs, comme l'affectation, doivent être membres.) Comme l'argument de gauche de l'opérateur de flux est un flux, les opérateurs de flux doivent être membres de la classe de flux ou des 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 pour diffuser par référence const. C'est parce que vous ne voulez pas copier l'objet pour le diffuser et que vous ne voulez pas que le streaming le modifie non plus.


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 la diffusion en continu

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

et appeler que 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_; 
}; 

de sorte qu'il puisse accéder aux parties privées de la classe:

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

Nice, réponse complète. –

+0

Accéder aux parties privées de la classe - Rawr. J/K, merci beaucoup, mais une question demeure: J'ai supprimé toutes les mentions à la surcharge sur le fichier d'en-tête ... mais je reçois l'erreur suivante (et seulement). 'binary '<<': aucun opérateur trouvé qui prend un opérande de droite de type 'Score' (ou il n'y a pas de conversion acceptable)' Comment se fait-il que mon test, dans main(), ne trouve pas l'approprié surcharge? (ce n'est pas les inclus). –

+1

Vous devez mettre la déclaration de l'opérateur << 'right avec la définition de votre classe: c'est dans le même en-tête et dans le même espace de noms. De cette façon, vous n'oublierez pas de l'inclure et le compilateur pourra le ramasser en cherchant des surcharges acceptables. –

9

Disons que vous vouliez écrire une surcharge de l'opérateur pour + vous pouvez donc ajouter deux Score objets à l'autre, et un autre, vous pouvez donc ajouter un int à un Score, et un troisième, vous pouvez donc ajouter un Score à un int . Celles où Score est le premier paramètre peuvent être des fonctions membres de Score. Mais celui où int est le premier paramètre ne peut pas devenir des fonctions membres de int, non? Pour vous aider, vous avez le droit de les écrire en tant que fonctions gratuites. C'est ce qui se passe avec cet opérateur <<, vous ne pouvez pas ajouter une fonction membre à ostream afin que vous écrivez une fonction gratuite. Voilà ce que cela signifie lorsque vous retirez la pièce Score::. Maintenant, pourquoi faut-il que ce soit friend? Ce n'est pas le cas. Vous n'appelez que des méthodes publiques (getPoints et scoreGetName). Vous voyez beaucoup d'opérateurs amis parce qu'ils aiment parler directement aux variables privées. C'est acceptable pour moi de le faire, car ils sont écrits et maintenus par la personne qui maintient la classe. Ne faites pas que la partie amie soit confuse avec la partie fonction-membre-vs-fonction-libre.

+0

Merci pour l'entrée supplémentaire! –

6

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 l'être la méthode a appelé), puis en lui donnant un supplément paramètre à la fin.

Lorsque vous appelez un opérateur binaire déclaré en tant que fonction membre, le côté gauche de l'expression est l'objet sur lequel la méthode est appelée. par exemple. a + b pourrait 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<< pour ostream est la seule façon de le faire dans ce cas, a + b pourrait fonctionner comme. ceci:

A a; 
B b 

operator+(a, b); 

Voici un exemple complet deux façons de le faire, main() affichera '55' trois fois:

#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; 
} 
Questions connexes