2011-10-16 11 views
39

Jest taki kod:funkcja przyjaciel dostępu zdefiniowane w klasie

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

Jak uzyskać dostęp do funkcji fun2()?

+6

+1: Dobrze sformułowane pytanie. –

+0

Ten rodzaj kodu znajduje się w inteligentnym wskaźniku doładowania: intrusive_ptr, co sprawiło, że najpierw zastanawiałem się, co to powinno być. Dla mnie nie ma sensu definiować tego w ten sposób, a raczej zdefiniować przyjaciela gdzieś w zasięgu i oznaczyć prototyp jako przyjaciela w deklaracji zakresu klasy, który jest bardziej czytelny! – Gabriel

Odpowiedz

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

Chociaż twoja definicja fun2ma zdefiniować funkcję „globalny”, zamiast członka i sprawia mu friend z A w tym samym czasie, nadal brakuje oświadczenie o tej samej funkcji w samym zasięgu globalnym.

Oznacza to, że żaden kod w tym zakresie nie ma pojęcia, że ​​istnieje fun2.

Ten sam problem występuje dla fun, z tym że wyszukiwanie zależne od argumentów może przejąć i znaleźć funkcję, ponieważ istnieje argument typu A.

Polecam zamiast definiowania funkcji w zwykły sposób:

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

Zawiadomienie teraz, że everything works (z wyjątkiem fun3 bo nigdy go zdefiniowano).

21

Powodem, dla którego można zadzwonić pod numer fun, jest to, że deklaracja przyjaciela w klasie A powoduje, że jest ona widoczna tylko poprzez wyszukiwanie zależne od argumentu. W przeciwnym razie deklaracje znajomych nie sprawiają, że funkcje, które deklarują, są automatycznie widoczne poza zakresem klasy, w którym się pojawiają.

Należy dodać deklarację w obszarze przestrzeni nazw lub wewnątrz main, aby fun2 było widoczne w main.

E.g.

void fun2(); 

fun3 jest widoczny wewnątrz main ponieważ jej definicja (poza klasą) jest również stwierdzenie, że sprawia, że ​​widoczne z main.

ISO/IEC 14882: 2011 7.3.1.2:

Nazwa znajomego nie zostanie znaleziony przez niewykwalifikowany odnośnika (3.4.1) lub przez wykwalifikowanego odnośnika (3.4.3) aż deklaracja jest dopasowanie w zakresie przestrzeni nazw (przed lub po definicji klasy nadającej przyjaźń).

3.4.2 (Argument zależny wyszukiwanie nazw)/4:

Wszelkie namespace-zakres funkcji przyjaciel lub znajomy szablony funkcyjne zadeklarowane w powiązanych klas są widoczne w ich odpowiednich nazw, nawet jeśli nie są one widoczne podczas zwykłego wyszukiwania (11.3).

+0

Umieszczenie deklaracji w globalnej przestrzeni nazw rozwiązuje problem, jednak umieszczenie go w głównej funkcji generuje błąd linkera. dzięki. – scdmb

+0

@scdmb: Jestem zaskoczony błędem linkera, powinien on być poprawny. –

+0

Nie, umieszczenie _definition-declaration_ w 'main' [powoduje błąd _kompilatora] (http://codepad.org/KrhX3kHL). [To, co Charles sugerował, jest dokładne] (http://codepad.org/ERZrmowu). Następnym razem należy dostarczyć testcase za każdym razem, gdy wrócisz z takim raportem o błędzie. Zobacz swoją książkę C++, aby zobaczyć różnicę między deklaracją a definicją. –

Powiązane problemy