2010-03-16 17 views
5

Cuando va a imprimir un objeto, se utiliza un operador amigo < <. ¿Podemos usar la función miembro para el operador < <?Por qué se prefiere la función de amigo a la función de miembro para el operador <<

class A { 

public: 
void operator<<(ostream& i) { i<<"Member function";} 
friend ostream& operator<<(ostream& i, A& a) { i<<"operator<<"; return i;} 
}; 


int main() { 

    A a; 
    A b; 
    A c; 
    cout<<a<<b<<c<<endl; 
    a<<cout; 
    return 0; 
} 

Un punto es que la función amigo nos permiten utilizar de esta manera

cout<<a<<b<<c 

qué otras razones?

+3

¿Realmente necesita alguna otra razón? –

+0

@mmyers: Intento entenderlo tan claro como puedo ... – skydoor

+1

Obviamente no puede ser una función miembro (ver la respuesta de Charles Bailey), pero no tiene que ser un * amigo * - si puedes implementarlo en términos de la interfaz pública de la clase, eso sería genial. – UncleBens

Respuesta

11

Debe utilizar una función libre y no una función de miembro, ya que para los operadores binarios, el lado izquierdo siempre es *this para las funciones miembro con el lado derecho pasado como el otro parámetro.

Para los operadores de flujo de salida, el lado izquierdo siempre es el objeto de flujo, por lo que si está transfiriendo a una clase estándar y no escribe el flujo usted mismo debe proporcionar una función gratuita y no un miembro de su clase.

Aunque sería posible proporcionar un operador de flujo hacia atrás como una función miembro y corriente a cabo de esta manera:

myObject >> std::cout; 

no sólo le violar una muy fuerte convención biblioteca, como usted señala, de encadenamiento de salida las operaciones no funcionarían debido a la agrupación de izquierda a derecha de >>.

Editar: Como han dicho otros, mientras que usted tiene que hacer es una función gratuita que sólo necesita ser un friend si la función de transmisión no puede ser implementada en términos de la clase interfaz pública.

10

No tiene elección, tiene que ser una función gratuita.

Tenga en cuenta, sin embargo, que no tiene que ser necesariamente una función friend. Solo necesita ser un amigo si realmente necesita otorgarle acceso privado. Por ejemplo, yo uso el siguiente en competiciones de programación:

template <class A, class B> 
std::ostream& operator<<(std::ostream& os, const std::pair<A, B>& p) 
{ 
    return os << '(' << p.first << ", " << p.second << ')'; 
} 

No hay necesidad de que sea amigo, como first y second son accesibles al público.

1

Otro motivo en su ejemplo - tiene que ser un friend porque esa es la única forma de definir una función libre dentro de la definición de la clase. Si quería una función libre de no amigos, debería definirse fuera de la clase.

¿Por qué prefiere definirlo en la clase? A veces es bueno para definir todos los operadores entre sí:

struct SomeClass { 
    // blah blah blah 
    SomeClass &operator+=(const SomeClass &rhs) { 
     // do something 
    } 
    friend SomeClass operator+(SomeClass lhs, const SomeClass &rhs) { 
     lhs += rhs; 
     return lhs; 
    } 
    // blah blah blah 
    // several pages later 
}; 

podría ser un poco más fácil de usar que:

struct SomeClass { 
    // blah blah blah 
    SomeClass &operator+=(const SomeClass &rhs) { 
     // do something 
    } 
    // blah blah blah 
    // several pages later 
}; 

SomeClass operator+(SomeClass lhs, const SomeClass &rhs) { 
    lhs += rhs; 
    return lhs; 
} 

Esto supone, por supuesto, que está definiendo las funciones miembro relacionadas en la definición de clase , en lugar de declararlos allí y definirlos en un archivo .cpp.

Editar: He usado + = y + como ejemplo sin pensar realmente en ello, pero su pregunta es acerca de operator<<, que no tiene operadores estrechamente relacionados como operator+. Pero si operator<< llama a una o más funciones miembro relacionadas con la impresión, es posible que desee definirlo cerca de donde están definidas.

0

No puede. Pero si no desea que sea una función de amigo, conviértala en una función gratuita e impleméntela en términos de la interfaz pública de la clase. Por ej.

ostream& operator<<(ostream& os, Myclass& obj) 
{ 
    return obj.print(os); 
} 

ostream& MyClass::print(ostream& os) 
{ 
    os << val; // for example. 
    return os; 
} 
Cuestiones relacionadas