Saltar a contenido

Funciones y clases amigas en C++

Funciones amigas

Una función amiga es una función externa de una clase que es capaz de acceder a los miembros privados de la misma. Para conseguirlo se declaran en la propia clase con la cláusula friend.

Si una función no es amiga no podremos hacer lo siguiente:

#include <iostream>

class Punto
{
private:
    double x{}, y{};
public:
    Punto(double x, double y) : x(x), y(y) {}
};

// Error al no tener acceso a los miembros
void print(const Punto &p)
{
    std::cout << "(" << p.x << ", " << p.y << ") "
              << "[" << &p << "]" << std::endl;
}

int main()
{    
    Punto p1(5, 4);
    print(p1);
    return 0;
}

Si la marcamos como amiga tendremos acceso a sus miembros:

#include <iostream>

class Punto
{
private:
    double x{}, y{};
public:
    Punto(double x, double y) : x(x), y(y) {}
    friend void print(const Punto &p); // ¡Soy amiga!
};

// Ahora funcionará porque somos amigos de la clase
void print(const Punto &p)
{
    std::cout << "(" << p.x << ", " << p.y << ") "
              << "[" << &p << "]" << std::endl;
}

int main()
{    
    Punto p1(5, 4);
    print(p1);  // (5, 4) [0x8d725ff700]
    return 0;
}

Consideraciones acerca de las funciones amigas:

  • Debe declararse primero en la clase y no importa donde esté definida mientras lo esté.
  • La clase determinará quién es amigo a través de la declaración.
  • No importa si se declara en la parte pública o privada.
  • Pueden tenerse múltiples funciones amigas y sobrecargarlas si es necesario.
  • Las funciones amigas no son funciones miembro.
  • Las funciones amigas no tienen acceso al puntero this.

Clases amigas

De forma similar al funcionamiento de las funciones amigas, una clase no tiene por defecto acceso a los miembros de otra.

Supongamos el siguiente ejemplo donde tenemos una clase Perro y una clase Gato, donde la clase Gato tiene un puntero a un objeto de tipo Perro llamado *amigoPerruno. Si bien podemos establecer el puntero mediante el método del gato setAmigoPerruno(), cuando queramos comprobar los miembros del perro no podremos hacerlo porque las clases Perro y Gato no son amigas por defecto:

#include <iostream>

class Perro
{
public:
    Perro(std::string nombre, int edad) 
        : nombre(nombre), edad(edad) {}

private:
    std::string nombre;
    int edad;
};

class Gato
{
public:
    Gato(std::string nombre, int edad)
        : nombre(nombre), edad(edad) {}

    void setAmigoPerruno(Perro *p)
    {
        this->amigoPerruno = p;
    }

    void amigo()
    {
        if (this->amigoPerruno)
        {
            // No podemos acceder a los miembros del perro
            std::cout << this->nombre << " es amigo de "
                << this->amigoPerruno->nombre << std::endl;
        }
        else
        {
            std::cout << this->nombre 
                << " no tiene amigos" << std::endl;
        }
    }

private:
    std::string nombre;
    int edad;
    Perro *amigoPerruno;
};

Si establecemos que Gato es amigo de Perro en la declaración de la clase:

class Perro
{
public:
    // Establecemos que Gato es una clase amigui
    friend class Gato;

    Perro(std::string nombre, int edad)
        : nombre(nombre), edad(edad) {}

private:
    std::string nombre;
    int edad;
};

Entonces podremos hacer algo como esto:

int main()
{
    Perro perro("Ronnie", 4);
    Gato gato("Sky", 2);

    gato.setAmigoPerruno(&perro);
    gato.amigos();

    Gato gatoSolitario("Nick", 8);
    gatoSolitario.amigos();

    return 0;
}
Sky es amigo de Ronnie
Nick no tiene amigos

Última edición: 09 de Mayo de 2022