funciones amigas - Oldemar Rodríguez Rojas
Transcripción
funciones amigas - Oldemar Rodríguez Rojas
Funciones y Clases Amigas en C++ Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional INTRODUCCIÓN A LAS FUNCIONES AMIGAS Habrá momentos en los que se quiera que una función tenga acceso a los miembros privados de una clase sin que esa función sea realmente un miembro de esa clase. De cara a esto, C++ soporta las funciones amigas. Una función amiga no es un miembro de una clase, pero tiene acceso a sus elementos privados. ¿Para qué sirven las funciones amigas? Dos motivos por los que las funciones amigas son útiles tienen que ver con la sobrecarga de operadores y la creación de ciertos tipos de funciones de E/S. Una tercera razón para las funciones amigas es que habrá momentos en los que una función tenga acceso a los miembros privados de dos o más clases diferentes. Este uso es el que se examina aquí. Una función amiga se define como una función no miembro normal. Sin embargo, dentro de la declaración de clase para la que será una función amiga, está también incluido su prototipo, precedido por la palabra clave friend. Para entender cómo funciona, examine este breve programa: #include <iostream.h> #include <conio.h> class myclass { int n, d; public: myclass(int i,int j) {n=i;d=j;} // declara una función amiga de myclass friend int isfactor(myclass ob); }; int isfactor(myclass ob) { if(!(ob.n % ob.d)) return 1; else return 0; } int main() { myclass ob1(10,2),ob2(13,3); if(isfactor(ob1)) cout << "2 es un factor de 10\n"; else cout << "2 no es un factor de 10\n"; if(isfactor(ob2)) cout << "3 es un factor de 13\n"; else cout << "3 no es un factor de 13\n"; char ch=getch(); return 0; } En este ejemplo, myclass declara su función constructora y la función amiga isfactor() dentro de su declaración de clase. Debido a que isfactor() es una función amiga de myclass, isfactor() tiene acceso a sus áreas privadas. Esto es por lo que dentro de isfactor(), es posible referirse directamente a ob.n y ob.d. Es importante entender que una función amiga no es un miembro de la clase de la que es amiga. Por lo tanto, no es posible llamar a una función amiga usando un nombre de objeto y un operador de acceso a miembro de clase (un punto o flecha). Por ejemplo, suponiendo el ejemplo sentencia está mal: ob1.isfactor(); // ERROR anterior, esta Las funciones amigas se llaman igual que las funciones normales. Aunque una función amiga tiene conocimiento de los elementos privados de la clase de la que es amiga, sólo puede acceder a ellos a través de un objeto de la clase. Es decir, a diferencia de un miembro de myclass, que se pueden referir directamente a n o d, una función amiga puede acceder a estas variables sólo en conjunción con un objeto que esté declarado dentro o pasado a la función amiga. Debido a que las funciones amigas no son miembros de una clase, normalmente se le pasarán uno o más objetos de la clase para la que están definidas. Una función amiga no es miembro y no se puede calificar mediante un nombre de objeto. Se tiene que llamar como una función normal. Una función amiga no se hereda. Es decir, cuando una clase base incluye una función amiga, la función amiga no es una función amiga de la clase derivada. Otro punto importante sobre las funciones amigas es que una función amiga puede ser amiga de más de una clase. Un uso común (y bueno) de una función amiga se da cuando dos tipos diferentes de clases tienen alguna cantidad en común que hay que comparar. Por ejemplo, considere el siguiente programa, que crea una clase llamada car y una clase llamada truck, cada una conteniendo, como una variable privada, la velocidad del vehículo que representa, veamos el siguiente ejemplo: Esto permite implementar relaciones de Asociación. #include <iostream.h> #include <conio.h> class truck; // una referencia anticipada class car { int passengers; int speed; public: car(int p,int s) {passengers=p;speed=s;} friend int sp_greater(car c, truck t); }; class truck { int weight; int speed; public: truck(int w,int s) {weight=w;speed=s;} friend int sp_greater(car c, truck t); }; int sp_greater(car c,truck t) { return c.speed-t.speed; } int main() { int t; car c1(6,55),c2(2,130); truck t1(10000,55), t2(20000,72); cout << "Comparando el y tl:\n"; t=sp_greater(c1,t1); if(t<0) cout <<"El camión es más rápido. \n"; else if(t==0) cout << "La velocidad del coche y del camión es la misma.\n"; else cout << "El coche es más rápido.\n"; cout << "\nComparando c2 y t2:\n"; t=sp_greater(c2,t2); if(t<0) cout << "El camión es más rápido.\n"; else if(t==0) cout << "La velocidad del coche y del camión es la misma.\n"; else cout << "El coche es más rápido.\n"; char ch=getch(); return 0; } Una función puede ser miembro de una clase y amiga de otra. Veamos el siguiente ejemplo: #include <iostream.h> #include <conio.h> class truck; // una referencia anticipada class car { int passengers; int speed; public: car(int p,int s) {passengers=p;speed=s;} int sp_greater(truck t); }; class truck { int weight; int speed; public: truck(int w,int s) {weight=w;speed=s;} friend int car::sp_greater(truck t); }; int car::sp_greater(truck t) { return speed - t.speed; } int main() { int t; car c1(6,55),c2(2,130); truck t1(10000,55), t2(20000,72); cout << "Comparando el y tl:\n"; t=c1.sp_greater(t1); if(t<0) cout <<"El camión es más rápido. \n"; else if(t==0) cout << "La velocidad del coche y del camión es la misma.\n"; else cout << "El coche es más rápido.\n"; cout << "\nComparando c2 y t2:\n"; t=c2.sp_greater(t2); if(t<0) cout << "El camión es más rápido.\n"; else if(t==0) cout << "La velocidad del coche y del camión es la misma.\n"; else cout << "El coche es más rápido.\n"; char ch=getch(); return 0; } Clases Amigas El caso más común de amistad se aplica a clases completas. El modificador “friend” puede aplicarse a clases o funciones para inhibir el sistema de protección. 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 también 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 míos. De nuevo, el símil es casi perfecto). La amistad no es simétrica. Si A es amigo de B, B no tiene por qué ser amigo de A. (En la vida real, una situación como esta hará peligrar la amistad de A con B, pero de nuevo me temo que en realidad se trata de una situación muy frecuente, y normalmente A no sabe que B no se considera su amigo). #include <iostream> using namespace std; class Amigable { private: int secreto; friend void FuncionAmiga(Amigable& o); friend class Amiga; }; class Amiga { public: void mirar(Amigable& o) { o.secreto = 120; cout << o.secreto << endl; } }; void FuncionAmiga(Amigable& o) { o.secreto = 121; cout << o.secreto << endl; } // Programa principal int main() { Amiga amiga; Amigable amigable; amiga.mirar(amigable); FuncionAmiga(amigable); system("pause"); system("cls"); return 0; } <Ver Ej1.CPP>