2011-10-16 8 views
39

Hay tal código:amigo función de acceso definido en la clase

#include <iostream> 

class A{ 

public: 
    friend void fun(A a){std::cout << "Im here" << std::endl;} 
    friend void fun2(){ std::cout << "Im here2" << std::endl; } 
    friend void fun3(); 
}; 

void fun3(){ 
    std::cout << "Im here3" << std::endl; 
} 

int main() 
{ 
    fun(A()); // works ok 
    //fun2(); error: 'fun2' was not declared in this scope 
    //A::fun2(); error: 'fun2' is not a member of 'A' 
    fun3(); // works ok 
} 

Cómo acceder a la función fun2()?

+6

+1: Pregunta bien formulada. –

+0

Vemos este tipo de código en el puntero inteligente de boost: intrusive_ptr, que me hizo en primer lugar resolver lo que debería ser. Para mí no tiene sentido definirlo de esa manera, más bien definir a un amigo en algún lugar del alcance y marcar un prototipo como amigo en la declaración de alcance de clase, ¡que es más legible! – Gabriel

Respuesta

34
class A{ 

public: 
    friend void fun(A a){std::cout << "Im here" << std::endl;} 
    friend void fun2(){ std::cout << "Im here2" << std::endl; } 
    friend void fun3(); 
}; 

Aunque su definición de fun2no definir una función "global" en lugar de un miembro, y lo convierte en un friend de A, al mismo tiempo, todavía se echa en falta una declaración de la misma función en el alcance global en sí.

Eso significa que ningún código en ese ámbito tiene idea de que fun2 existe.

Ocurre lo mismo con fun, excepto que Argument-Dependent Lookup puede hacerse cargo y encontrar la función, porque hay un argumento del tipo A.

Recomiendo lugar la definición de sus funciones en la forma habitual:

class A { 
    friend void fun(A a); 
    friend void fun2(); 
    friend void fun3(); 
}; 

void fun(A a) { std::cout << "I'm here" << std::endl; } 
void fun2() { std::cout << "I'm here2" << std::endl; } 
void fun3(); 

Aviso ahora que everything works (excepto fun3 porque nunca se la he definido).

21

La razón por la que puede llamar al fun es que la declaración de amigo dentro de la clase A la hace visible solo mediante búsqueda dependiente de argumentos. De lo contrario, las declaraciones de amigos no hacen que las funciones que declaran sean automáticamente visibles fuera del alcance de la clase donde aparecen.

Debe agregar una declaración al alcance del espacio de nombres o dentro de main para que fun2 sea visible en main.

E.g.

void fun2(); 

fun3 es visible en el interior main porque su definición (fuera de la clase) es también una declaración que hace que sea visible desde main.

ISO/IEC 14882: 2011 7.3.1.2:

El nombre del amigo que no se encuentra en las operaciones de búsqueda no calificado (3.4.1) o mediante operaciones de búsqueda cualificado (3.4.3) hasta que una declaración es coincidente proporcionado en ese ámbito de espacio de nombres (ya sea antes o después de la definición de clase que otorga amistad).

3.4.2 (Argumento dependiente de búsqueda de nombre)/4:

Cualquier espacio de nombres alcance funciones amigas o plantillas de función amigo declarados en clases asociadas son visibles dentro de sus respectivos espacios de nombres, incluso si no están visible durante una búsqueda ordinaria (11.3).

+0

colocar la declaración en el espacio de nombres global resuelve el problema; sin embargo, al colocarlo en la función principal se genera un error de enlazador. Gracias. – scdmb

+0

@scdmb: estoy sorprendido por el error del enlazador, debería ser válido. –

+0

No, colocando _definition-declaration_ en 'main' [causa un _compiler_ error] (http://codepad.org/KrhX3kHL). [Lo que Charles sugirió es correcto] (http://codepad.org/ERZrmowu). Y la próxima vez proporcione un caso de prueba cada vez que regrese con un informe de errores como ese. Consulte su libro de C++ para ver la diferencia entre una declaración y una definición. –

Cuestiones relacionadas