funciones ‘amigo’ y << sobrecarga del operador: ¿cuál es la forma correcta de sobrecargar un operador para una clase?

En un proyecto en el que estoy trabajando, tengo una clase de Score , que se define a continuación en score.h . Estoy tratando de sobrecargarlo así que, cuando se realiza una operación << , se _points + " " + _name .

Esto es lo que traté de hacer:

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

Aquí están los errores devueltos:

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

(Este error aparece 4 veces, en realidad)

Pude hacerlo funcionar declarando la sobrecarga como una función amiga:

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

Y eliminando el Score:: de la statement de función en score.cpp (de hecho no lo declara como miembro).

¿Por qué funciona esto, pero la antigua pieza de código no?

¡Gracias por tu tiempo!

EDITAR

Eliminé todas las menciones de la sobrecarga en el archivo de encabezado … pero recibo el siguiente (y único) error. binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion) ¿Cómo es que mi prueba, en main (), no puede encontrar la sobrecarga adecuada? (No es el incluye, lo he comprobado)

A continuación se muestra la puntuación completa.h

 #ifndef SCORE_H_ #define SCORE_H_ #include  #include  #include  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 

Nota: Es posible que desee consultar las preguntas frecuentes sobre sobrecarga del operador .


Los operadores binarios pueden ser miembros de la clase de su argumento de la izquierda o funciones libres. (Algunos operadores, como la asignación, deben ser miembros). Dado que el argumento de la izquierda de los operadores de flujo es una secuencia, los operadores de flujo deben ser miembros de la clase de flujo o de las funciones gratuitas. La forma canónica de implementar operator<< para cualquier tipo es esto:

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

Tenga en cuenta que no es una función miembro. También tenga en cuenta que lleva el objeto a la transmisión por referencia const . Esto se debe a que no desea copiar el objeto para poder transmitirlo y tampoco desea que la transmisión lo altere.


Algunas veces desea transmitir objetos cuyas funciones internas no son accesibles a través de la interfaz pública de su clase, por lo que el operador no puede acceder a ellas. Luego tiene dos opciones: poner un miembro público en la clase que hace la transmisión

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

y llamarlo desde el operador:

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

o hacer que el operador sea un friend

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

para que pueda acceder a las partes privadas de la clase:

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

Supongamos que desea escribir una sobrecarga de operador para + modo que pueda agregar dos objetos de Score entre sí, y otro para agregar un int a un Score , y un tercero para poder agregar un Score a un int . Aquellos en los que un Score es el primer parámetro pueden ser funciones miembro de puntaje. Pero aquel en el que un int es el primer parámetro no puede convertirse en funciones miembro de int , ¿verdad? Para ayudarte con eso, puedes escribirlos como funciones gratuitas. Eso es lo que está sucediendo con este operador << , no puede agregar una función de miembro para ostream para que escriba una función gratuita. Eso es lo que significa cuando quitas la parte Score:: .

Ahora, ¿por qué tiene que ser un friend ? No es así Solo está llamando a métodos públicos ( getPoints y scoreGetName ). Ves muchos amigos operadores porque les gusta hablar directamente con las variables privadas. Estoy bien que lo haga, porque la persona que mantiene la clase la escribe y la mantiene. Simplemente no mezcle parte del amigo con la parte miembro función-vs-función libre.

Está obteniendo errores de comstackción cuando el operator<< es una función miembro en el ejemplo porque está creando un operator<< que toma un Score como el primer parámetro (el objeto al que se llama el método), y luego le da un extra parámetro al final.

Cuando llamas a un operador binario declarado como función miembro, el lado izquierdo de la expresión es el objeto al que se llama el método. por ejemplo, a + b podría funcionar así:

 A a; B b a.operator+(b) 

Por lo general, es preferible utilizar operadores binarios no miembros (y en algunos casos, por ejemplo, el operator<< para ostream es la única forma de hacerlo. En ese caso, a + b podría funcionar así:

 A a; B b operator+(a, b); 

Aquí hay un ejemplo completo que muestra ambas formas de hacerlo; main () generará '55' tres veces:

 #include  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; } 
Intereting Posts