51 - Clases amigas (friend)


Otra posibilidad en C++ es que una clase sea amiga. Esto hace que todos los métodos de la clase amiga tengan acceso a los atributos privados y protegidos.

Problema:

Declarar dos clases independientes: Nodo y ListaGenerica. En la clase nodo definir el atributo info, los punteros sig y ant e indicar que tiene una clase amiga llamada ListaGenerica por lo que tendrá acceso a sus atributos.

Programa:

#include<iostream>

using namespace std;

class Nodo {
    int info;
    Nodo *ant, *sig;
public:
    Nodo(int x){ info = x; };
    friend class ListaGenerica;
};


class ListaGenerica {
    Nodo *raiz;
public:
    ListaGenerica() { raiz = NULL; };
    ~ListaGenerica();
    void insertarPrimero(int x);
    void imprimir();
};

ListaGenerica::~ListaGenerica()
{
    Nodo *reco = raiz;
    Nodo *bor;
    while (reco != NULL)
    {
        bor = reco;
        reco = reco->sig;
        delete bor;
    }
}

void ListaGenerica::insertarPrimero(int x)
{
    Nodo *nuevo = new Nodo(x);
    nuevo->ant = NULL;
    if (raiz == NULL)
    {
        nuevo->sig = NULL;
        raiz = nuevo;
    }
    else
    {
        nuevo->sig = raiz;
        raiz->ant = raiz;
        raiz = nuevo;
    }
}

void ListaGenerica::imprimir()
{
    Nodo *reco = raiz;
    while (reco != NULL)
    {
        cout << reco->info << "-";
        reco = reco->sig;
    }
    cout << "\n";
}


int main()
{
    ListaGenerica *lista1 = new ListaGenerica();
    lista1->insertarPrimero(10);
    lista1->insertarPrimero(20);
    lista1->insertarPrimero(5);
    lista1->imprimir();
    delete lista1;
    return 0;
}

Este proyecto lo puede descargar en un zip desde este enlace : ClaseAmiga1.zip

Declaramos la clase Nodo definiendo los atributos info,ant y sig en la parte privada, esto significa que no podrán ser accedidos desde métodos fuera de la clase, pero hacemos la excepción con la clase ListaGenerica indicando que se trata de una clase amiga (friend class):

class Nodo {
    int info;
    Nodo *ant, *sig;
public:
    Nodo(int x){ info = x; };
    friend class ListaGenerica;
};

Esta característica hace que dentro de la clase ListaGenerica podamos acceder a los atributos privados y protegidos sin problemas:

    Nodo *nuevo = new Nodo(x);
    nuevo->ant = NULL;

Si bien se podrían haber definido métodos para acceder a dichos atributos lo más eficiente a nivel de ejecución es acceder a los mismos directamente.

En la declaración de la clase ListaGenerica no hay ninguna referencia a la otra clase, solo definimos el puntero raiz que tendrá la dirección al primer nodo de la lista:

class ListaGenerica {
    Nodo *raiz;
public:
    ListaGenerica() { raiz = NULL; };
    ~ListaGenerica();
    void insertarPrimero(int x);
    void imprimir();
};

Ahora en el método insertarPrimero podemos crear un objeto de la clase Nodo y acceder a sus tres atributos privados sin problema mediante el operador ->:

void ListaGenerica::insertarPrimero(int x)
{
    Nodo *nuevo = new Nodo(x);
    nuevo->ant = NULL;
    if (raiz == NULL)
    {
        nuevo->sig = NULL;
        raiz = nuevo;
    }
    else
    {
        nuevo->sig = raiz;
        raiz->ant = raiz;
        raiz = nuevo;
    }
}

En conceptos anteriores vimos el tema de listas y planteamos dentro de la clase ListaGenerica una clase interna llamada Nodo.

Puede haber situaciones donde la clase Nodo convenga declararla fuera de la clase ListaGenerica y luego otras clases puedan acceder a los atributos privados de la misma mediante el modificador friend class.

Las clases amigas deben utilizarse en situaciones especiales ya que deteriora el concepto de encapsulamiento de nuestra aplicación.

Retornar