2010-10-03 27 views
9

Siento que tengo un pequeño hueco en mi comprensión de la palabra clave friend.amigo en el operador == o << ¿cuándo debería usarlo?

Tengo una clase, presentation. Yo lo uso en mi código de dos variables, present1 y present2, que yo comparo con ==:

if(present1==present2) 

Así es como lo define el operador == (en class presentation):

bool operator==(const presentation& p) const; 

Sin embargo, yo estaba dijo que el uso de friend y definir fuera de la clase es mejor:

friend bool operator==(presentation&, presentation&); 

Por qué ? ¿Cuál es la diferencia entre los dos?

+0

-1 incompleto y bot comprensible –

+2

Para mí es perfectamente comprensible. ¿Debería el operador == ser una función amiga fuera de una clase, o definida dentro de la clase? – Benoit

+0

Un bot puede entender esta pregunta? > _> – Rao

Respuesta

2

En el primer caso, su función operator== es un miembro de clase no estático. Por lo tanto, tiene acceso a variables miembro privadas y protegidas.

En el segundo caso, el operador está declarado externamente, por lo tanto, debe definirse como un amigo de la clase para acceder a esas variables miembro.

+1

Bien, pero ¿por qué querría que se declarara de manera externa? ¿aún lo hace de forma externa aunque la declaración se encuentre dentro de la clase como pública? y es el primero bueno también? – Nadav

+0

Ambos funcionan. Pero en el segundo caso, la función no es parte de la clase, incluso si pudiera estar en el mismo archivo de encabezado. – Benoit

1

Me gusta la respuesta de Benoit (pero no puedo votarla), pero me parece que un ejemplo no estaría de más aclararla. Aquí hay un código dinero que tengo (asumir todo lo demás se coloca a la derecha):

// header file 
friend bool operator ==(const Money, const Money); // are the two equal? 

// source file 
bool operator ==(const Money a1, const Money a2) 
{ 
    return a1.all_cents == a2.all_cents; 
} 

Espero que ayude.

11

Su solución funciona, pero es menos poderosa que el enfoque friend.

Cuando una clase declara una función u otra clase como friend, significa que la clase o la función de amigo tiene acceso a los miembros privados y protegidos de la clase declarante. Es como si la entidad declarada fuera un miembro de la clase declarante.

Si define operator==() como una función miembro, entonces al igual que con el caso friend, la función miembro tiene acceso completo a los miembros de la clase. Pero como es una función miembro, especifica un único parámetro, ya que implica que el primer parámetro es this: un objeto del tipo presentation (o un descendiente del mismo). Sin embargo, si define la función como no miembro, puede especificar ambos parámetros, y esto le dará la flexibilidad de comparar dos tipos que se puedan convertir en presentation usando esa misma función.

Por ejemplo:

class presentation { 
    friend bool operator==(const presentation&, const presentation&); 
    // ... 
}; 

class Foo : public presentation { /* ... */ }; 
class Bar : public presentation { /* ... */ }; 

bool operator==(const presentation& p1, const presentation& p2) 
{ 
    // ... 
} 

bool func(const Foo& f, const Bar& b, const presentation& p) 
{ 
    return f == b || f == p); 
} 

Por último, esto plantea la pregunta "¿por qué la declaración friend?". Si la función operator==() no necesita acceso a miembros privados de presentation, entonces la mejor solución es hacer que sea una función no miembro, no amiga. En otras palabras, no otorgue a una función privilegios de acceso que no es necesario.

+0

Creo que efectivamente se reduce a una cuestión de estilo. Si uno siempre hace que el operador sobrecargue las funciones de amigo externo (incluso cuando no es necesario), entonces todas las sobrecargas del operador estarán "juntas" fuera de la clase. –

+0

thnx mucho +1. Supongo que no puedo marcar 2 respuestas. – Nadav

+0

@Emile: Creo que se reduce a la funcionalidad, como dice Wilhelmtell. Si implementa miembro 'operator ==' (y otros operadores), cuando lo usa obtiene conversión implícita en rhs, pero no en lhs. Si lo implementa como una función que no es miembro, obtiene conversión implícita en ambos. El estilo está muy bien, pero hay algunos operadores que no pueden sobrecargarse con funciones que no son miembros, por lo que solo te lleva hasta cierto punto. –

0

Tome un vistazo a este sorta duplicar aquí: should-operator-be-implemented-as-a-friend-or-as-a-member-function

Lo que es importante señalar, esta pregunta es ligado sobre << y >> que debería aplicarse como amigos ya que los dos operandos son diferentes tipos.

En su caso, tiene sentido implementarlo como parte de la clase. La técnica de amigo se usa (y es útil) para casos en los que se usa más de un tipo y, a menudo, no se aplica a == y !=.

0

Un operador implementado como un método, solo se puede llamar, si la expresión del lado izquierdo es una variable (o una referencia al objeto) de la clase, el operador se define para.

Por lo general, le interesa comparar dos objetos de la misma clase. La implementación, como método, resuelve su problema aquí.

Imagínese sin embargo, que se escribe una clase string y desea un operador, para trabajar en este escenario:

const char *s1 = ... 
MyString s2 = ... 
if(s1 == s2){... 

Para que la expresión s1 == s2 legal, usted tiene que definir un opetator== como una función externa a MyString clase.

bool operator==(const char *, const MyString&); 

Si el operador necesita un acceso a los miembros privados de su clase, tiene que ser un amigo de su clase.

En el caso de los operadores << y >>, que funcionan en las transmisiones, usted define un operador, cuyo operando izquierdo es una instancia de flujo y el correcto es su clase, por lo que no pueden ser métodos de su clase. Como en el ejemplo anterior, tienen que ser funciones externas a su clase y amigos, si se requiere el acceso a miembros privados.

Cuestiones relacionadas