2011-10-07 25 views
8

Tengo una clase base y luego varias clases derivadas. Me gustaría sobrecargar el operador "< <" para estas clases derivadas. Para los operadores normales, es decir, '+', las funciones virtuales hacen el truco. Lo que yo entiendo que es la convención estándar es declararsobrecarga << operadores y clases heredadas

friend ostream& operator<<(ostream& out, MyClass& A); 

dentro de mi clase y luego definir la función después de la clase. A priori, creo que agregar virtual a la definición anterior lo haría funcionar, pero después de pensar un poco (y los errores de mi compilador) me doy cuenta de que no tiene mucho sentido.

Probé una táctica diferente en un caso de prueba, donde todos los miembros de la clase son públicos. Por ejemplo:

class Foo{ 
//bla 
}; 

ostream& operator<<(ostream& out, Foo& foo){ 
    cout << "Foo" << endl; 
    return foo; 
} 

class Bar : public Foo{ 
//bla 
}; 

ostream& operator<<(ostream& out, Bar& bar){ 
    cout << "Bar" << endl; 
    return bar; 
} 

/////////////////////// 

Bar bar = Bar(); 
cout << bar << endl; // outputs 'Foo', not 'Bar' 

Así que de alguna manera esto es "polimorfismo ido mal" - el operador clase base < < que se llama en lugar del operador de clase derivada. En el ejemplo anterior, ¿cómo hago que se llame al operador correcto para la clase derivada? Y, en términos más generales, si mi clase tiene miembros privados que deseo proteger, ¿cómo puedo corregir la sobrecarga del operador al usar la palabra clave friend?

Respuesta

6

Puede usar una función de ayudante virtual. Aquí está un ejemplo, no está comprobado, por lo excusa los errores de sintaxis:

virtual ostream& Foo::print(ostream& out) const { 
    return out << "Foo"; 
} 

virtual ostream& Bar::print(ostream& out) const { 
    return out << "Bar"; 
} 

// If print is public, this doesn't need to be a friend. 
ostream& operator<<(ostream& out, const Foo& foo) { 
    return foo.print(out); 
} 

Editar: limpiado por @Omnifarious sugerencias.

+0

Funciona a la perfección. Gracias. – andyInCambridge

+0

Creo que esto tiene dos defectos. Un defecto es un gran defecto, y el otro es un defecto menor. Enorme defecto primero ... nunca deberías poner invisiblemente 'endl'. 'endl' obliga a una descarga de flujo, que puede ser un gran problema de rendimiento en algunas circunstancias. Use ''\ n''. Está garantizado que es igual de portable (de hecho, 'endl' se define en términos de salida ''\ n'', y no incurre en gastos indirectos. En segundo lugar, yo haría esto:' return out << "Foo \ n ";' Se siente un poco más limpio. Conceptualmente convierte todo en una larga cadena de operaciones << <<. – Omnifarious

+0

@Omnifarious Nunca pondría 'endl' en una' sobrecarga 'operador <<. Solo estaba siguiendo el código de OP. –

1

Realice operator<< una función gratuita que reenvía la llamada a un método virtual de la clase Foo.

See it in action.

+0

¡Sí, esto funciona! Gracias. – andyInCambridge

2

Por lo general, solo crea un método polimórfico print en la clase base que se llama con una única función de amigo libre.

+0

Si la impresión es pública, podemos deshacernos del amigo. –

+0

Buenos puntos, gracias. – andyInCambridge

1

Con las correcciones de código adecuadas en su lugar, su código funciona bien; nada que hacer:

ostream& operator<<(ostream& out, Foo& foo) { 
    out << "Foo" << endl; // 'out' and not 'cout' 
    return out; // returns 'out' and not 'foo' 
} 

ostream& operator<<(ostream& out, Bar& bar) { 
    out << "Bar" << endl; // 'out' and not 'cout' 
    return out; // returns 'out' and not 'bar' 
} 

Demo. Para acceder a los miembros private, puede hacer que esta función sea friend en el class deseado.

+1

intrigante. En realidad, mi código se había usado correctamente en lugar de cout, pero todavía no funcionaba. Debe haber algo sutil que no esté capturado por las clases relleno // bla. – andyInCambridge

Cuestiones relacionadas