Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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).
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
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 */
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;
}
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();
}