Sei sulla pagina 1di 6

I

Sistema de proteccin
Ya sabemos que los miembros privados de una clase no son accesibles para funciones y clases exteriores a
dicha clase. Esto es un concepto de POO, el encapsulamiento hace que cada objeto se comporte de un
modo autnomo y que lo que pase en su interior sea invisible para el resto de objetos. Cada objeto slo
responde a ciertos mensajes y proporciona determinadas salidas.
Pero, en ciertas ocasiones, querremos poder acceder a determinados miembros privados de un objeto de
una clase desde otros objetos de clases diferentes. C++ proporciona un mecanismo para sortear el sistema
de proteccin. En otros captulos veremos la utilidad de esta tcnica, de momento slo explicaremos en qu
consiste.

Declaraciones friend
El modificador "friend" puede aplicarse a clases o funciones para inhibir el sistema de proteccin.
Las relaciones de "amistad" entre clases son parecidas a las amistades entre personas:
La amistad no puede transferirse, si A es amigo de B, y B es amigo de C, esto no implica que A sea
amigo de C. (La famosa frase: "los amigos de mis amigos son mis amigos", es falsa en C++, y
probablemente tambin en la vida real).
La amistad no puede heredarse. Si A es amigo de B, y C es una clase derivada de B, A no es amigo de
C. (Los hijos de mis amigos, no tienen por qu ser amigos mos. De nuevo, el smil es casi perfecto).

La amistad no es simtrica. Si A es amigo de B, B no tiene por qu ser amigo de A. (En la vida real, una
situacin como esta har peligrar la amistad de
#include <iostream.h>
A con B, pero me temo que en realidad, se
#include <stdlib.h>
trata de una situacin muy frecuente).

Funciones externas amigas


El caso ms sencillo es el de una relacin de
amistad con una funcin externa.
Veamos un ejemplo muy sencillo:
Como puedes ver, la funcin "Ver", que no
pertenece a la clase A puede acceder al miembro
privado de A y visualizarlo. Incluso podra
modificarlo.
No parece que sea muy til, verdad?. Bueno,
seguro que en alguna ocasin tiene aplicaciones
prcticas.

class A {
private:
int a;
friend void Ver(A); // "Ver" es amiga de la clase A
public:
A(int i=0) {a = i;} // constructor
void Ver() {cout << a << endl;}
};
void Ver(A Xa)
{
// La funcin Ver puede acceder a miembros privados
// de la clase A, ya que ha sido declarada "amiga" de A
cout << Xa.a << endl;
}
int main(int argc, char *argv[])
{
A Na(10);
Ver(Na); // Ver el valor de Na.a
Na.Ver(); // Equivalente a la anterior
system("PAUSE");
return 0;
}

II

Funciones amigas en otras clases


El siguiente caso es ms comn, se trata de cuando la funcin amiga forma parte de otra clase. El proceso
es ms complejo. Veamos otro ejemplo:
#include <iostream.h>
#include <stdlib.h>
class A; // Declaracin previa (forward)
class B {
private:
int b;
public:
B(int i=0) {b = i;}
void Ver() {cout << b << endl;}
bool EsMayor(A Xa); // Compara b con a
};
class A {
public:
A(int i=0) {a = i;}
void Ver() {cout << a << endl;}
private:
// Funcin amiga tiene acceso a miembros privados
de la clase A
friend bool B::EsMayor(A Xa);
int a;
};

bool B::EsMayor(A Xa)


{
return b > Xa.a;
}
int main(int argc, char *argv[])
{
A Na(10);
B Nb(12);
Na.Ver();
Nb.Ver();
if(Nb.EsMayor(Na)) cout << "Nb es mayor que Na" <<
endl;
else cout << "Nb no es mayor que Na" << endl;
system("PAUSE");
return 0;
}

Puedes comprobar lo que pasa si eliminas la lnea donde se declara "EsMayor" como amiga de A.
Es necesario hacer una declaracin previa de la clase A (forward) para que pueda referenciarse desde la
clase B.
Veremos que estas "amistades" son tiles cuando sobrecarguemos algunos operadores.

Clases amigas.
El caso ms comn de amistad se aplica a clases completas. Lo que sigue es un ejemplo de
implementacin de una lista dinmica mediante el uso de dos clases "amigas".
La clase Lista puede acceder a todos los miembros de Elemento, sean o no pblicos, pero desde la funcin
"main" slo podemos acceder a los miembros pblicos de nuestro elemento.
Para poder introducir este ejemplo he usado algunos conceptos que an no hemos explicado, como los
punteros a objetos, o el uso de los operadores new y delete con clases, pero creo que vale la pena para
demostrar que la amistad entre clases tiene una aplicacin prctica.

III
#include <iostream.h>
#include <stdlib.h>
/* Clase para elemento de lista enlazada */
class Elemento {
private:
/* Datos: */
int tipo;
/* Tipo */
Elemento *sig;
/* Siguiente elemento */
friend class Lista;
/* Amistad con lista */
public:
Elemento(int t);
int Tipo() { return tipo;}
};

/* Constructor */
/* Obtener tipo */

/* Clase para lista enlazada de nmeros*/


class Lista {
private:
/* Puntero al primer elemento */
Elemento *Cabeza;
/* Funcin privada para borrar lista */
void LiberarLista();

/* Borra todos los elementos de la lista */


void Lista::LiberarLista()
{
Elemento *p;
while(Cabeza){
p = Cabeza;
Cabeza = p->sig;
delete p;
}
}
int main(int argc, char *argv[])
{
Lista miLista;
Elemento *e;
// Insertamos varios valores en la lista
miLista.Nuevo(4);
miLista.Nuevo(2);
miLista.Nuevo(1);

public:
/* Constructor inline */
Lista()
{
Cabeza = NULL;
/* Lista vaca */
}
~Lista() {LiberarLista();}
/* Destructor inline */
void Nuevo(int tipo);
/* Insertar figura */
/* Obtener primer elemento */
Elemento *Primero() {return Cabeza;}
/* Obtener el siguiente elemento a p */
Elemento *Siguiente(Elemento *p)
{ if (p) return p->sig; else return p;};
/* Si p no es NULL */
bool EstaVacio() { return Cabeza == NULL;
}
/* Averiguar si la lista est vaca */
};
/* Constructor */
Elemento::Elemento(int t)
{
tipo = t; /* Asignar datos desde lista de parmetros */
sig = NULL;
}
/* Aadir nuevo elemento al principio de la lista */
void Lista::Nuevo(int tipo)
{
Elemento *p;
p = new Elemento(tipo); /* Nuevo elemento */
p->sig = Cabeza;
Cabeza = p;
}

// Y los mostramos en pantalla:


e = miLista.Primero();
while(e) {
cout << e->Tipo() << " ,";
e = miLista.Siguiente(e);
}
cout << endl;
system("PAUSE");
return 0;
}

IV

V
// Suma de numeros complejos con clases y sobrecarga de operador +, = y sobrecarga de funciones miembro
# include<iostream.h>
# include<conio.h>
# include<stdio.h>
class complejo // clase complejo
{
private :
double real ;
double imag ;
public:
complejo(){ real = 0.0 ; imag = 0.0;}; // constructor
//funciones miembro en linea para asignar y visualizar datos
void asigna(float A, float B){ real=A; imag=B;cout<<"flotantes\n";}
void asigna(int A, int B){ real=A; imag=B;cout<<"enteros\n";}
void ver(){ cout<< " ("<<real<< ","<<imag<<"i)";}
//prototipo de sobrecarga de operador + para complejos
complejo operator+(complejo C);
//prototipo de sobrecarga de operador = para complejos
complejo operator=(complejo C);
};
// fin de clase complejo
complejo complejo::operator+(complejo C)
{
complejo temp;
temp.real=(real + C.real );
temp.imag=(imag + C.imag);
return temp;
} // esta funcion miembro es creada por omision en C++ aunque puede crearse y utilizar this, siendo redundate.
// La operacion de asignacion es una de los usos m s importantes del puntero this. Aqui el objeto que produce la
// activacin de la funcin operador se pasa implcitamente mediante el puntero this.
complejo complejo::operator=(complejo C)
{
real= C.real ;
imag= C.imag;
return *this;
}
void main()
{
complejo I,J,K,R;
float X1,Y1,X2,Y2; int x1,y1,x2,y2;
clrscr();
cout<< "Programa que suma dos numeros complejos flotantes"<<endl;
cout<< "Teclear la parte real y despues la imaginaria"<<endl;
cout<< "X1 = "; cin>> X1; cout<< "Y1 = "; cin>> Y1;
cout<< "X2 = "; cin>> X2; cout<< "Y2 = "; cin>> Y2;
I.asigna(X1,Y1);
J.asigna(X2,Y2);
// uso de la sobrecarga del operador + para suma de complejos
// y sobrecarga del operador = para asingnacion de objetos
K=I+J;
cout<< "\n Resultado Z1 + Z2 = ";
K.ver();
// sobrecarga dos veces el operador +
R.asigna(X1,Y2);
K=J+I+R;
cout<< "\n Z3 = (X1,Y2) datos anteriores, reasignados";
cout<< "\n Resultado Z2 + Z1 + Z3 = ";
K.ver();
getch();
// sobrecarga de funciones miembro

VI
cout<< "\n\nPrograma que suma dos numeros complejos enteros"<<endl;
cout<< "Teclear la parte real y despues la imaginaria"<<endl;
cout<< "X1 = "; cin>> x1;
cout<< "Y1 = "; cin>> y1;
cout<< "X2 = "; cin>> x2;
cout<< "Y2 = "; cin>> y2;
I.asigna(x1,y1);
J.asigna(x2,y2);
// uso de la sobrecarga del operador + para suma de complejos
// y sobrecarga del operador = para asingnacin de objetos
K=I+J;
cout<< "\n Resultado Z1 + Z2 = ";
K.ver();
getch();
}

Potrebbero piacerti anche