funciones 'amigo' << sobrecarga de operadores: ¿Cuál es la forma correcta de sobrecargar un operador para una clase?

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

Pregunta

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

Esto es lo que he intentado 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)

Me las arreglé para conseguir que funcione, al declarar la sobrecarga en función amigo:

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

Y la eliminación de la Score:: de la declaración de la función en score.cpp (de hecho, no se declara como un miembro).

¿Por qué este trabajo, sin embargo, la antigua pieza de código no?

Gracias por su tiempo!

Editar

He eliminado todas las menciones a la sobrecarga en el archivo de cabecera ... todavía tengo la (y único) de error siguiente. 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 apropiada? (Que no es lo incluye, he comprobado)

A continuación se score.h completa

#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
¿Fue útil?

Solución

Nota: Es posible que desee ver el sobrecarga de operadores Preguntas .


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

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

Tenga en cuenta que es no una función miembro. También tenga en cuenta que se tarda el objeto de transmitir por referencia const. Esto se debe a que no desea copiar el objeto con el fin de transmitir y que no desea que la transmisión de alterarlo tampoco.


A veces se quiere transmitir objetos cuyas partes internas no son accesibles a través de su clase interfaz pública, por lo que el operador puede no llegar a ellos. Entonces usted tiene dos opciones: o bien poner un miembro del público en la clase que realiza la transmisión

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

y llamada que desde el operador:

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

o hacer que el operador de un friend

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

para que pueda acceder a las partes íntimas de la clase:

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

Otros consejos

Digamos que quería escribir una sobrecarga del operador para + por lo que podría agregar dos objetos Score el uno al otro, y otro por lo que podría añadir una int a un Score, y un tercero por lo que podría añadir un Score a un int. Aquellos en los que un Score es el primer parámetro pueden ser funciones miembro de Score. Pero aquel en el que un int es el primer parámetro no puede convertirse en funciones miembro de int, ¿verdad? Para ayudar con esto, se le permite escribir como funciones gratuitas. Eso es lo que está sucediendo con este operador <<, no se puede agregar una función miembro de ostream así se escribe una función libre. Eso es lo que significa cuando se quita la parte Score::.

Ahora, ¿por qué tiene que ser un friend? No lo hace. Sólo se está llamando a métodos públicos (getPoints y scoreGetName). Ves un montón de operadores amigo porque les gusta hablar directamente a las variables privadas. Está bien por que lo haga, porque están escritos y mantenidos por la persona maintaing la clase. Sólo no conseguir el papel amigo, confuso, con la parte de miembro de funciones-vs-free-función.

que está recibiendo errores de compilación cuando operator<< es una función miembro en el ejemplo, porque va a crear un operator<< que toma un Score como primer parámetro (el objeto del método de ser llamados), y luego dándole un parámetro extra al final.

Cuando se está llamando a un operador binario que se declara como una función miembro, el lado izquierdo de la expresión es el objeto del método que se llama sucesivamente. p.ej. fuerza a + b funciona así:

A a;
B b

a.operator+(b)

Es normalmente preferible utilizar operadores binarios no miembros (y en algunos casos - por ejemplo operator<<for ostream es la única manera de hacerlo En ese caso, el trabajo a + b pueden gustar esto:.

A a;
B b

operator+(a, b);

Aquí está un ejemplo completo que muestra ambas formas de hacerlo; principal () de salida será '55' tres veces:

#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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top