c++ - relacionales - sobrecarga del operador++
C++ Resumen sobrecarga de operador de clase y pregunta de aplicaciĆ³n de interfaz (5)
A los operadores de stream les gusta:
virtual ostream& operator<<(ostream& stream, const BaseMessage objectArg) = 0;
simplemente no pueden ser funciones miembro, y tampoco pueden ser funciones virtuales. La razón de esto es que cuando dices algo como:
a << b;
realmente estás diciendo
a.operator<<( b );
En este caso a es una secuencia, no una instancia de su clase, por lo que el operador no puede ser miembro de su clase. Por lo general, debe convertirla en una función gratuita (no miembro), que acceda a su instancia de clase a través de funciones miembro adecuadas.
(editado de la publicación original para cambiar "BaseMessage" a "const BaseMessage &")
Hola a todos, soy muy nuevo en C ++, así que espero que ustedes puedan ayudarme a "ver los errores de mis maneras".
Tengo una jerarquía de mensajes y estoy tratando de usar una clase base abstracta para imponer una interfaz. En particular, quiero forzar que cada mensaje derivado proporcione un operador << sobrecargado.
Cuando intento hacer esto con algo como esto:
class BaseMessage
{
public:
// some non-pure virtual function declarations
// some pure virtual function declarations
virtual ostream& operator<<(ostream& stream, const BaseMessage& objectArg) = 0;
}
el compilador se queja de que
"error: no se puede declarar el parámetro ''objectArg'' como de tipo abstracto ''BaseMessage''
Creo que también hay problemas de "amigos" involucrados aquí, pero cuando intenté declararlo como:
virtual friend ostream& operator<<(ostream& stream, const BaseMessage objectArg) = 0;
el compilador añadió un error de adición
"error: las funciones virtuales no pueden ser amigas"
¿Hay alguna manera de asegurar que todas mis clases derivadas (mensaje) proporcionen un operador ostream "<<"?
Muchas gracias,
Steve
El problema aquí es que "BaseMessage objectArg" está diciendo que el objeto objectArg debe pasarse por valor.
Esto es imposible ya que ha hecho la clase abstracta con su llamada virtual pura. Un paso por referencia "BaseMessage & objectArg" o un paso por puntero "BaseMessage * objectArg" haría que este error desapareciera.
Pasar por valor significa que crea una nueva instancia de la variable utilizando el constructor de copia. Ya que se aseguró de que es imposible crear una instancia de BaseMessage, esto no se puede hacer.
La clase abstracta no puede ser instanciada, así que haz esto:
virtual ostream& operator<<(ostream& stream, const Base &objectArg) = 0;
La función virtual debe ser una función miembro de instancia, mientras que la función amiga no es una función miembro, por lo que no puede declararse como virtual
De manera similar, la función estática no puede ser virtual, ya que es un método de clase, no de instancia.
Mi sugerencia es :
class Base {
public:
virtual ostream& print (ostream& stream) const = 0;
};
class Derived :public Base {
public:
virtual ostream& print (ostream& stream) const { //do something }
};
ostream& operator <<(ostream& stream, const BaseMessage &objectArg)
{
return objectArg.print(stream);
}
La convención común para esto es tener un operador de salida friend
en el nivel base y hacer que llame a la función virtual privada:
class Base
{
public:
/// don''t forget this
virtual ~Base();
/// std stream interface
friend std::ostream& operator<<( std::ostream& out, const Base& b )
{
b.Print( out );
return out;
}
private:
/// derivation interface
virtual void Print( std::ostream& ) const =0;
};
La declaración para el operador << () es incorrecta. Para la versión binaria de op <<, no tiene que declarar el segundo parámetro; se supone que es this
si op << es una función miembro de la clase:
virtual ostream& operator<<(ostream& stream) = 0;
Además, como han mencionado otros, los operadores de inserción de flujos tienen que ser funciones globales. Hacerlos funciones de miembro simplemente no funcionará.
Además, no es algo que no esté relacionado con su pregunta, pero sin embargo un problema. En su implementación original, pasó un objeto de clase base abstracta por valor, en lugar de por referencia o por puntero. Cuando haces esto, "cortas el objeto". Su intención, estoy seguro, era pasar un puntero de clase base a un tipo polimórfico a la función, y luego tener los métodos de llamada de función polimorfos. Por ejemplo, intentabas hacer algo similar a esto:
#include <cstdio>
#include <string>
#include <iostream>
using namespace std;
class Base
{
public:
virtual void dump()
{
cout << "Base";
};
};
class Der : public Base
{
public:
void dump()
{
cout << "Der";
};
};
void DumpIt(Base b)
{
b.dump();
}
int main()
{
Der obj;
DumpIt(obj);
return 0;
}
... y esperando que la salida sea "Der" Pero, de hecho, la salida es "Base" debido a la segmentación de objetos . Debido a que la función DumpIt () toma el objeto Base por valor, se crea un nuevo objeto Base temporal basado en el original. Para obtener la funcionalidad que esperaba, debe pasar por referencia o por puntero:
void DumpIt(Base & b)
{
b.dump();
}
La salida de esta función es "Der".