Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: digimikeh en 1 Marzo 2019, 00:16 am



Título: Funciones Friends y Namespaces..
Publicado por: digimikeh en 1 Marzo 2019, 00:16 am
Hola!

Me parece extraño que tenga que definir una función friend anteponiendo el espacio de nombre si se supone que lo dejé estipulado al principio:

Código
  1. //Persona.h
  2.  
  3. namespace Agenda{
  4.   class Persona{
  5.  
  6.      int edad;
  7.      friend int f_obtenerEdad();
  8.  
  9.   };
  10. }
  11.  

Código
  1. //Persona.cpp
  2. #include "Persona.h"
  3. using namespace Agenda;
  4.  
  5. int f_obtenerEdad(Persona & _p){
  6.   return _p.edad;          //Error, edad es privado
  7. }
  8.  


En cambio, si lo hago asi:
Código
  1. //Persona.cpp
  2. #include "Persona.h"
  3. using namespace Agenda;
  4.  
  5. int Agenda::f_obtenerEdad(Persona & _p){
  6.   return _p.edad;         //Esto lo asimila correctamente
  7. }
  8.  


Tenía entendido que si yo escribía "using namespace X", no era necesario llamar a los miembros de un objeto usando X:: , pero en este caso del friend no se cumple, por qué será?

Gracias..


Título: Re: Funciones Friends y Namespaces..
Publicado por: K-YreX en 1 Marzo 2019, 00:40 am
Esto es porque estás declarando el prototipo de la función <f_obtenerEdad()> dentro del <namespace Agenda> pero la implementación de la función lo estás haciendo fuera; lo que sea hace confuso.

Para que funcione correctamente debes hacer que tanto el prototipo como la implementación pertenezcan al <namespace Agenda>.
Código
  1. namespace Agenda{
  2.    class Persona{
  3.        int edad;
  4.        public:
  5.            friend int f_obtenerEdad(const Persona&);
  6.    };
  7.  
  8.    int f_obtenerEdad(const Persona &p){
  9.        return p.edad;
  10.    }
  11. }

Al hacerlo en ficheros separados debes especificar que la implementación también pertenece al <namespace Agenda> por eso que tienes que ponerlo para que funcione.
Puedes leer un poco más al respecto  AQUÍ  (https://stackoverflow.com/questions/44749878/warning-defining-friend-operator-declared-inside-a-namespace) :-X


Título: Re: Funciones Friends y Namespaces..
Publicado por: digimikeh en 1 Marzo 2019, 01:21 am
Pero por lo visto esto solo sucede con las funciones amigas verdad?


Título: Re: Funciones Friends y Namespaces..
Publicado por: K-YreX en 1 Marzo 2019, 01:44 am
No, he probado a crear una función simple para probar y te dejaré por aquí el código y las salidas que genera.

Código
  1. #include <iostream>
  2.  
  3. namespace Agenda{
  4. class Persona{
  5. public:
  6. int a;
  7. Persona():a(5){}
  8. };
  9. int f(const Persona&);
  10. }
  11.  
  12. using namespace Agenda;
  13.  
  14. int main(){
  15. Persona p1;
  16. std::cout << f(p1) << std::endl;
  17. }
  18.  
  19. int f(const Persona &p){
  20. return p.a;
  21. }

La salida para este caso es un error de compilación:
Código:
En la función `main':
test.cpp:(.text+0x2b): referencia a `Agenda::f(Agenda::Persona const&)' sin definir
collect2: error: ld returned 1 exit status

Este error se puede solucionar añadiendo el <namespace Agenda> a la implementación de la función tal que:
Código
  1. int Agenda::f(const Agenda::Persona &p){
  2.    return p.a;
  3. }



En cambio, si ponemos la función dentro del <namespace>...
Código
  1. #include <iostream>
  2.  
  3. namespace Agenda{
  4. class Persona{
  5. public:
  6. int a;
  7. Persona():a(5){}
  8. };
  9.  
  10. int f(const Persona &p){
  11. return p.a;
  12. }
  13. }
  14.  
  15. using namespace Agenda;
  16.  
  17. int main(){
  18. Persona p1;
  19. std::cout << f(p1) << std::endl;
  20. }

La salida en este caso sí es la correcta:
Código:
Salida: 5 


Título: Re: Funciones Friends y Namespaces..
Publicado por: digimikeh en 1 Marzo 2019, 02:33 am
Ok, pero ahí estas declarando una funcion fuera de la clase, yo decía lo de friend porque se declara dentro de la clase, aunque no sea miembro.


Título: Re: Funciones Friends y Namespaces..
Publicado por: Loretz en 1 Marzo 2019, 05:03 am
En tu ejemplo, la declaración de f_obtenerEdad() y su definición son distintas (en otros bares podrían decirte que es más respetuoso poner ejemplos que compilen).

Yo veo dos cosas, una es que las formas habituales de definir una función friend son
1) "inline", directamente en el cuerpo de la clase, y
2) en un archivo cpp, ampliando el mismo namespace. (Abajo pongo esta alternativa).

La otra es que puedes tener dos funciones (sobrecarga) con la misma firma, una friend en el mismo namespace de la clase, y otra no friend y global, y en este caso con using namespace... el compilador no sabría a cuál de las dos te refieres.

Acá abajo va un ejemplo:

Código
  1. // en Agenda.h
  2. namespace Agenda {
  3.    class Persona {
  4.        int edad = 42;
  5.        friend int f_obtenerEdad(Persona& _p);
  6.  
  7.    public:
  8.        int sumaEdad(int i)
  9.        {
  10.            return edad + i;
  11.        }
  12.    };
  13. }
  14.  
  15. // Mejor que la de abajo
  16. // en Agenda.cpp
  17. namespace Agenda {
  18.    int f_obtenerEdad(Persona& p)
  19.    {
  20.        return p.edad;
  21.    }
  22. }
  23.  
  24. /*
  25. // Menos mejor que la de arriba
  26. int Agenda::f_obtenerEdad(Agenda::Persona& _p)
  27. {
  28.     return _p.edad;
  29. }
  30. */
  31.  
  32.  
  33. // otra pero global:
  34. int f_obtenerEdad(Agenda::Persona& _p)
  35. {
  36.    return _p.sumaEdad(5);
  37. }
  38.  
  39.  
  40.  
  41.  
  42. #include <iostream>
  43.  
  44. int main()
  45. {
  46.    Agenda::Persona p;
  47.    std::cout << Agenda::f_obtenerEdad(p) << '\n';
  48.  
  49.    std::cout << ::f_obtenerEdad(p) << '\n'; // usa la versión global
  50. }


Título: Re: Funciones Friends y Namespaces..
Publicado por: digimikeh en 2 Marzo 2019, 02:14 am
Me queda claro, gracias a ambos.. :rolleyes: