ah
#include "logic.h"
...
class A
{
friend ostream& operator<<(ostream&, A&);
...
};
logic.cpp
#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...
Cuando compilo, dice:
std :: ostream & logic :: operator << (std :: ostream &, A &) 'debe tomar exactamente un argumento.
¿Cuál es el problema?
c++
operator-overloading
iostream
Como como
fuente
fuente
Una función de amigo no es una función miembro, por lo que el problema es que declaras
operator<<
como amigo deA
:friend ostream& operator<<(ostream&, A&);
luego intente definirlo como una función miembro de la clase
logic
ostream& logic::operator<<(ostream& os, A& a) ^^^^^^^
¿Está confundido acerca de si
logic
es una clase o un espacio de nombres?El error se debe a que ha intentado definir un miembro
operator<<
tomando dos argumentos, lo que significa que toma tres argumentos, incluido elthis
parámetro implícito . El operador solo puede tomar dos argumentos, de modo que cuando escribea << b
los dos argumentos sona
yb
.Se desea definir
ostream& operator<<(ostream&, const A&)
como no la función -miembro, definitivamente no como miembro delogic
puesto que no tiene nada que ver con esa clase!std::ostream& operator<<(std::ostream& os, const A& a) { return os << a.number; }
fuente
Me encontré con este problema con las clases basadas en plantillas. Aquí hay una solución más general que tuve que usar:
template class <T> class myClass { int myField; // Helper function accessing my fields void toString(std::ostream&) const; // Friend means operator<< can use private variables // It needs to be declared as a template, but T is taken template <class U> friend std::ostream& operator<<(std::ostream&, const myClass<U> &); } // Operator is a non-member and global, so it's not myClass<U>::operator<<() // Because of how C++ implements templates the function must be // fully declared in the header for the linker to resolve it :( template <class U> std::ostream& operator<<(std::ostream& os, const myClass<U> & obj) { obj.toString(os); return os; }
Ahora: * Mi función toString () no puede estar en línea si va a estar escondida en cpp. * Estás atascado con un código en el encabezado, no pude deshacerme de él. * El operador llamará al método toString (), no está en línea.
El cuerpo del operador << se puede declarar en la cláusula friend o fuera de la clase. Ambas opciones son feas. :(
Tal vez estoy entendiendo mal o me estoy perdiendo algo, pero simplemente declarar que la plantilla del operador no se vincula en gcc.
Esto también funciona:
template class <T> class myClass { int myField; // Helper function accessing my fields void toString(std::ostream&) const; // For some reason this requires using T, and not U as above friend std::ostream& operator<<(std::ostream&, const myClass<T> &) { obj.toString(os); return os; } }
Creo que también puede evitar los problemas de plantillas que obligan a las declaraciones en los encabezados, si usa una clase principal que no tiene una plantilla para implementar el operador <<, y usa un método toString () virtual.
fuente
Si la define
operator<<
como función miembro, tendrá una sintaxis descompuesta diferente a la que tendría si usara una función no miembrooperator<<
. Un no miembrooperator<<
es un operador binario, donde un miembrooperator<<
es un operador unario.// Declarations struct MyObj; std::ostream& operator<<(std::ostream& os, const MyObj& myObj); struct MyObj { // This is a member unary-operator, hence one argument MyObj& operator<<(std::ostream& os) { os << *this; return *this; } int value = 8; }; // This is a non-member binary-operator, 2 arguments std::ostream& operator<<(std::ostream& os, const MyObj& myObj) { return os << myObj.value; }
Entonces ... ¿cómo los llamas realmente? Los operadores son extraños de alguna manera, te desafiaré a que escribas la
operator<<(...)
sintaxis en tu cabeza para que las cosas tengan sentido.MyObj mo; // Calling the unary operator mo << std::cout; // which decomposes to... mo.operator<<(std::cout);
O puede intentar llamar al operador binario que no es miembro:
MyObj mo; // Calling the binary operator std::cout << mo; // which decomposes to... operator<<(std::cout, mo);
No tiene la obligación de hacer que estos operadores se comporten de manera intuitiva cuando los convierte en funciones miembro, puede definir
operator<<(int)
desplazamiento a la izquierda de alguna variable miembro si lo desea, comprenda que las personas pueden estar un poco desprevenidas, sin importar cuántos comentarios pueda hacer escribir.Casi por último, puede haber ocasiones en las que ambas descomposiciones para una llamada de operador sean válidas, puede tener problemas aquí y aplazaremos esa conversación.
Por último, tenga en cuenta lo extraño que podría ser escribir un operador de miembro unario que se supone que debe verse como un operador binario (ya que puede hacer que los operadores de miembro sean virtuales ..... también intentando no delegar y ejecutar esta ruta ... )
struct MyObj { // Note that we now return the ostream std::ostream& operator<<(std::ostream& os) { os << *this; return os; } int value = 8; };
Esta sintaxis irritará a muchos programadores ahora ...
MyObj mo; mo << std::cout << "Words words words"; // this decomposes to... mo.operator<<(std::cout) << "Words words words"; // ... or even further ... operator<<(mo.operator<<(std::cout), "Words words words");
Observe cómo
cout
es el segundo argumento de la cadena aquí ... ¿extraño verdad?fuente