2011-10-16 9 views
39

C'è tale codice:funzione friend di accesso definiti in classe

#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 
} 

Come accedere alla funzione fun2()?

+6

+1: domanda ben formulata. –

+0

Vediamo questo tipo di codice nel puntatore intelligente di boost: intrusive_ptr, che mi ha fatto prima capire quale dovrebbe essere. Per me non ha senso definirlo in questo modo, piuttosto definire un amico da qualche parte nel campo di applicazione e contrassegnare un prototipo come amico nella dichiarazione dell'ambito di classe, che è più leggibile! – Gabriel

risposta

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(); 
}; 

Anche se la tua definizione di fun2non definire una funzione "globale", piuttosto che un membro, e ne fa una friend di A, allo stesso tempo, si sta ancora manca una dichiarazione della stessa funzione nello scopo globale stesso.

Ciò significa che nessun codice in tale ambito ha alcuna idea che esista fun2.

Lo stesso problema si verifica per fun, ad eccezione del fatto che la ricerca dipendente dall'argomento può prendere il sopravvento e trovare la funzione, poiché esiste un argomento di tipo A.

vi consiglio invece di definire le funzioni nel modo consueto:

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(); 

Notate ora che everything works (tranne fun3 perché non ho mai definito esso).

21

Il motivo per cui è possibile chiamare fun è che la dichiarazione di amicizia all'interno della classe A lo rende visibile solo tramite ricerca dipendente dall'argomento. Altrimenti le dichiarazioni di amici non rendono automaticamente visibili le funzioni che dichiarano al di fuori dell'ambito di classe in cui appaiono.

È necessario aggiungere una dichiarazione nello spazio dei nomi o all'interno di main per rendere visibile fun2 in main.

E.g.

void fun2(); 

fun3 è visibile all'interno main perché la sua definizione (fuori della classe) è anche una dichiarazione che rende visibile da main.

ISO/IEC 14882: 2011 7.3.1.2:

Il nome di un amico non si trova dalla ricerca senza riserve (3.4.1) o di ricerca qualificato (3.4.3) fino a una dichiarazione di corrispondenza è fornito nello scope namespace (prima o dopo la definizione della classe che garantisce l'amicizia).

3.4.2 (Argument-dependent ricerca del nome)/4:

Qualsiasi spazio dei nomi-scope funzioni friend o modelli amico funzione dichiarata in classi associate sono visibili nei loro rispettivi spazi dei nomi, anche se non sono visibile durante una normale ricerca (11.3).

+0

la dichiarazione di immissione nello spazio dei nomi globale risolve il problema, tuttavia collocarlo nella funzione principale genera un errore del linker. Grazie. – scdmb

+0

@scdmb: Sono sorpreso dall'errore del linker, dovrebbe essere valido. –

+0

No, posizionare la _definition-declaration_ in 'main' [causa un errore _compiler_] (http://codepad.org/KrhX3kHL). [Ciò che Charles ha suggerito è accurato] (http://codepad.org/ERZrmowu). E la prossima volta fornisci un test ogni volta che torni con un rapporto di errore del genere. Vedi il tuo libro C++ per la differenza tra una dichiarazione e una definizione. –

Problemi correlati