¿Por qué es posible colocar definiciones de funciones amigas dentro de una definición de clase?

7 minutos de lectura

Avatar de usuario de Hossein
Hossein

¿No se supone que una función amiga se define explícitamente fuera de una clase?
Si es así, ¿por qué puedo declarar una función amiga dentro de una definición de clase como cualquier función miembro?
Qué es esto ?
¿Está bien solo con algunos operadores como < operador o es aplicable a todos los operadores?
Si es aplicable a todos ellos, ¿hay alguna desventaja por hacer esto?
¿Debe evitarse? Si es así, ¿por qué?

class person 
{
public:
    bool operator<(int num)
    {
        return  x < num ? true : false ;
    }
    bool operator<(person& p)
    {
        return  x < p.x ? true : false ;
    }

    friend bool operator<(int num, person &p)
    {
        return  p.x < num ? true : false ;
    }

    void setX(int num)
    {
        x = num;
    }

private:
    int x;


};

Actualizar:
No estoy pidiendo elegir la sobrecarga de operadores no miembros o la sobrecarga de operadores miembros.
Lo que quiero saber es que:
¿Por qué se nos permite mover el definición de métodos amigos dentro de nuestra definición de clase?.
¿No es violar ninguna cosa? Si no es así, ¿por qué tendríamos amigos en primer lugar?
Podríamos simplemente definir las sobrecargas como funciones miembro (conozco las limitaciones de las funciones miembro) Pero digo sabiendo esto, ¿Por qué el compilador no se queja de que no he definido la función de amigo fuera de una definición de clase? ya que no necesita estar dentro de él (debido al parámetro de clase que tiene) Entonces, ¿por qué se nos permite definir una función amiga dentro de una definición de clase?

  • Si usted está preguntando acerca de la definición de la friend función, entonces debe cambiar el título de su pregunta para reflejar eso.

    – juanchopanza

    7 de julio de 2013 a las 13:47

  • ¿Qué debo escribir entonces?

    – Hossein

    7 de julio de 2013 a las 13:52

  • Puede hacerlo porque el estándar lo permite explícitamente. En cuanto a la razón por la cual el estándar lo permite, supongo que se consideró lo suficientemente conveniente como para que valiera la pena.

    -Vaughn Cato

    7 julio 2013 a las 13:53

  • Puede preguntar “¿por qué es posible colocar definiciones de funciones amigas dentro de una definición de clase?”

    – juanchopanza

    7 de julio de 2013 a las 13:54

Avatar de usuario de Alexandru Barbarosie
Alejandro Barbarosie

¿No se supone que una función amiga se define explícitamente fuera de una clase?

Las funciones amigas se pueden definir (dado un cuerpo de función) dentro de declaraciones de clase. Estas funciones son funciones en línea y, al igual que las funciones en línea de miembros, se comportan como si se hubieran definido inmediatamente después de que se hayan visto todos los miembros de la clase, pero antes de que se cierre el ámbito de la clase (el final de la declaración de la clase). Las funciones amigas que se definen dentro de las declaraciones de clase están en el ámbito de la clase adjunta.
cotizar

¿Está bien solo con algunos operadores como

Es mejor tratar de evitar las funciones amigas ya que son opuestas a lo que está tratando de hacer usando un alcance de clase privada y principalmente “ocultar” las variables. Si todas sus funciones son funciones amigas, ¿de qué sirve tener variables privadas?

Aún así, hay algunos operadores comunes que a menudo se declaran como funciones amigas, esos son operator<< y operator>>

  • Muchas gracias 🙂 No estoy tratando de declarar todas mis funciones necesarias como amigos, tenía curiosidad por saber por qué una función amiga (que se usa únicamente para operar sobrecarga y nada más) se puede definir dentro de una clase y por qué esta permitido

    – Hossein

    7 de julio de 2013 a las 13:49

  • @Hossein, la cita que le di en realidad no dice “por qué está permitido”, pero explica por qué “no está permitido”.

    – Alexandru Barbarosie

    7 de julio de 2013 a las 13:52

  • lo sé, pero la parte “Las funciones de amigos se pueden definir dentro de las declaraciones de clase”, dice que estamos autorizados a hacerlo, entiendo que las funciones de amigos no son una respuesta para todo, como también lo mencionó claramente, cuando estaba diciendo eso, yo significaba la sección citada que aclaraba partes de mi pregunta

    – Hossein

    7 julio 2013 a las 14:01

  • ¿Están “en el alcance del archivo”? ¿No deberían insertarse en el ámbito circundante, ya sea archivo, espacio de nombres, función, clase?

    – Félix Dombek

    20 de febrero de 2019 a las 14:34

  • Friend functions that are defined inside class declarations are in the scope of the enclosing class. No estoy seguro de que esta parte sea precisa. Al menos no puedo detectar ninguna diferencia entre las funciones amigas definidas dentro de una declaración de clase y fuera de ella; ambas actúan como funciones libres sin restricción de alcance adicional.

    – El viento de los sueños

    10 oct a las 16:07


Avatar de usuario de Blasco
Blasco

La respuesta de Alexandru Barbarosie es correcta. Significa que podemos declarar una función amiga, que no es una función miembro, dentro de una clase. Esto puede ser bueno para organizar el código. Creo que un ejemplo puede ayudar a entenderlo en caso de que no quede claro.

#include <iostream>

class A {
    public:
        A(int val) : val(val) {}
        // The following isn't a member function, it is a friend 
        // function declared inside the class and it has file scope
        friend void draw (A &a) {
            std::cout << "val: " << a.val << "\n";
        }
    private:
        int val;
};

int main() {
    A a(5);
    draw(a); // outputs "val: 5"
    //A::draw(a); // Error: 'draw' is not a member of 'A'
}

Si está creando una clase de solo encabezado (lo que hace que la implementación sea mucho más fácil), entonces definir una función amiga dentro de la clase es la única forma de hacerlo, ya que las definiciones solo pueden aparecer en una sola unidad de traducción. La técnica normal de include guards no funciona, ya que solo maneja cosas como la inclusión recursiva.

Esto puede ser un gran problema si está tratando de escribir código que cumpla con los estándares. Por ejemplo, para implementar la MotorNúmeroAleatorio requisito mencionado del estándar normativo de C++, es necesario proporcionar operator<<. Esto tiene que ser un friend para tomar un std::ostream& object como su primer parámetro (de lo contrario, se verá como una sobrecarga de operador de función de miembro de parámetro único normal). Normalmente el friend declaración iría en la definición de clase y la definición de función en un separado .cpp archivo fuente. Pero si desea una implementación de solo encabezado, debe definirse en la clase para evitar múltiples errores de definición.

  • “definir una función de amigo dentro de la clase es el único camino a seguir” También se podría usar inline funciones

    – Santo Gato Negro

    24 oct 2019 a las 19:26

  • @HolyBlackCat cierto, hasta cierto punto. Sin embargo, no estoy feliz de hacer esto, ya que las líneas en línea con enlaces no estáticos no necesitan ser las mismas en todas las unidades de traducción, y eso es solo un problema. Por un operadortiene sentido mantener la definición tan estrechamente asociada con su clase como sea posible.

    – David G.

    24 oct 2019 a las 19:53

Avatar de usuario de Jack
Jacobo

Debido a que un operador necesita conocer los detalles del lado derecho de la expresión en la que se usa, si debe acceder a datos privados del tipo que reside en ese lado, debe ser friend con esa clase.

Si está tratando de comparar un int con un personcomo en su ejemplo, las opciones son dos:

  • usted proporciona una conversión implícita de person a int de modo que < puede usarlo sin acceder a ningún campo privado.
  • o declaras al operador como friend de person para que pueda acceder x en el lado derecho de la comparación.

Como Jack mencionó, las funciones de amigo son necesarias en lugares donde se necesita acceso a datos privados. También hay otro propósito. Esto está relacionado con los tipos de herencia. Solo la clase derivada y sus amigos pueden convertir un puntero a una base privada en un tipo derivado. Por lo tanto, es posible que a veces desee hacer que alguna función sea amiga de la clase derivada para permitir este cuerpo de función interno.

¿Ha sido útil esta solución?