Así que tienen una interfaz de streaming virtual en C++Problemas con interfaz de flujo en C++
class KxStream
{
public:
virtual KxStream& operator<< (u32 num) = 0;
};
Tiene una tonelada de < básicos < operadores para todos los tipos incorporados. Acabo de enumerar uno.
Luego tengo algunas clases que implementan la interfaz de transmisión. De esta manera:
class KxCbuf : public KxStream
{
public:
KxStream& operator<<(u32 num);
}
lo que es una implementación de la interfaz de streaming en KxCbuf. Hasta aquí todo bien. Entonces tengo algunas clases que sobrecargan la interfaz de tren:
class KxSymbol
{
operator u32() const;
friend KxStream& operator<<(KxStream& os, KxSymbol sym);
};
Tenga en cuenta que esta clase ha echado a un operador de tipo incorporado. Ahora en que intento transmitir a una de estas clases en una de las clases que implementan la interfaz de streaming consigo un error:
KxCbuf buf;
KxSymbol sym;
buf << sym; // error!
El compilador se confunde sobre qué funciones utilizar. Gcc compila bien, pero dice que hay varias maneras de hacer esto. MSVC no compila diciendo que hay múltiples sobrecargas:
src/variable.cpp(524) : error C2666: 'KxCbuf::operator <<' : 15 overloads have similar conversions
sé lo que está pasando, pero no la forma de resolver de manera satisfactoria. Entonces el compilador puede lanzar KxCbuf -> KxStream, y luego llamar a la función de amigo, que es lo correcto. O puede emitir KxSymbol -> u32, y luego llamar al operador u32 < < en KxCbuf, heredado de KxStream.
Lo puedo resolver de dos (malas) maneras.
puedo empezar por el streaming en algo ambigua:
buf << "" << sym;
De esta manera el valor de retorno del primer operador corriente de "" retorno KxStream, y todo está bien. O puedo implementar un operador de flujo redundante para la clase de implementación. P.ej. Puedo añadir lo siguiente a KxSymbol:
friend KxStream& operator<<(KxCbuf& os, KxSymbol sym);
La primera respuesta siempre funciona - pero seguro que es feo. La segunda respuesta también es desagradable, ya que tengo que crear operadores de flujo redundantes, y no siempre funciona porque las implementaciones de KxStream no siempre son visibles en los lugares donde necesito definir nuevos operadores de flujo.
Idealmente me gustaría que las implementaciones de la interfaz KxStream funcionen igual que los objetos KxStream, y evite conversiones implícitas que causen conversiones ambiguas.
¿Cómo soluciono esto?
(ps tengo que crear mis propios operadores de transmisión para un esquema de serialización personalizado para mi biblioteca no puedo usar impulso o bibliotecas de terceros similares que tienen sus propias clases de serialización..)
@Edit: No hay varias buenas respuestas relacionadas con el control del uso de la conversión implícita del compilador, como la conversión a KxSymbol -> u32, desafortunadamente esa conversión implícita es importante para el código. Por ejemplo, KxSymbol es una clase que almacena cadenas en una tabla y las devuelve como números para que pueda comparar cadenas como números. P.ej. si dos símbolos no son iguales, entonces las cadenas no son lo mismo.También almaceno símbolos como números en algunas estructuras de datos.
¿Hay alguna manera de resolver esto desde el otro lado, de alguna manera hacer que el compilador entienda que las implementaciones de KxStream deben ser convertidas a objetos KxStream por preferencia a otras versiones implícitas?
Por ejemplo, ¿y si yo de alguna manera obligar al compilador a tener que echar primera KxCbuf a KxStream antes de usar el operador < < de la incorporada en los tipos. Esto haría que siempre prefiera el operador de sobrecarga < < sobre los KxStream. - las sobrecargas requerirían un lanzamiento, y las de KxStream requerirían dos.
¿Qué sucede si pasa el 'KxSymbol sym' por const reference en lugar de copiar? Eso podría corregir el problema –