Funciones Friends y Namespaces..

Iniciado por digimikeh, 1 Marzo 2019, 00:16 AM

0 Miembros y 1 Visitante están viendo este tema.

digimikeh

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 (cpp) [Seleccionar]

//Persona.h

namespace Agenda{
  class Persona{
     
     int edad;
     friend int f_obtenerEdad();

  };
}


Código (cpp) [Seleccionar]

//Persona.cpp
#include "Persona.h"
using namespace Agenda;

int f_obtenerEdad(Persona & _p){
  return _p.edad;          //Error, edad es privado
}



En cambio, si lo hago asi:
Código (cpp) [Seleccionar]

//Persona.cpp
#include "Persona.h"
using namespace Agenda;

int Agenda::f_obtenerEdad(Persona & _p){
  return _p.edad;         //Esto lo asimila correctamente
}



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..
Dungeons & dragons;
dragons.Attack();

K-YreX

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 (cpp) [Seleccionar]

namespace Agenda{
    class Persona{
        int edad;
        public:
            friend int f_obtenerEdad(const Persona&);
    };

    int f_obtenerEdad(const Persona &p){
        return p.edad;
    }
}


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Í :-X
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

digimikeh

Pero por lo visto esto solo sucede con las funciones amigas verdad?
Dungeons & dragons;
dragons.Attack();

K-YreX

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 (cpp) [Seleccionar]

#include <iostream>

namespace Agenda{
class Persona{
public:
int a;
Persona():a(5){}
};
int f(const Persona&);
}

using namespace Agenda;

int main(){
Persona p1;
std::cout << f(p1) << std::endl;
}

int f(const Persona &p){
return p.a;
}


La salida para este caso es un error de compilación:

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 (cpp) [Seleccionar]

int Agenda::f(const Agenda::Persona &p){
    return p.a;
}





En cambio, si ponemos la función dentro del <namespace>...
Código (cpp) [Seleccionar]

#include <iostream>

namespace Agenda{
class Persona{
public:
int a;
Persona():a(5){}
};

int f(const Persona &p){
return p.a;
}
}

using namespace Agenda;

int main(){
Persona p1;
std::cout << f(p1) << std::endl;
}


La salida en este caso sí es la correcta:

Salida: 5
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

digimikeh

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.
Dungeons & dragons;
dragons.Attack();

Loretz

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 (cpp) [Seleccionar]
// en Agenda.h
namespace Agenda {
    class Persona {
        int edad = 42;
        friend int f_obtenerEdad(Persona& _p);

    public:
        int sumaEdad(int i)
        {
            return edad + i;
        }
    };
}

// Mejor que la de abajo
// en Agenda.cpp
namespace Agenda {
    int f_obtenerEdad(Persona& p)
    {
        return p.edad;
    }
}

/*
// Menos mejor que la de arriba
int Agenda::f_obtenerEdad(Agenda::Persona& _p)
{
    return _p.edad;
}
*/


// otra pero global:
int f_obtenerEdad(Agenda::Persona& _p)
{
    return _p.sumaEdad(5);
}




#include <iostream>

int main()
{
    Agenda::Persona p;
    std::cout << Agenda::f_obtenerEdad(p) << '\n';

    std::cout << ::f_obtenerEdad(p) << '\n'; // usa la versión global
}

digimikeh

Dungeons & dragons;
dragons.Attack();