2012-05-11 17 views
13

Zgodnie z książką C++ Primer, autor wspomniał, że możemy określić funkcję członka klasy jako przyjaciela innej klasy, zamiast całej klasy (strona 634).Określ funkcję członka klasy jako przyjaciela innej klasy?

Następnie testowałem ten kod:

class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 
class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 

Chciałem tylko FB(), aby być przyjacielem klasy A, nie cała klasa B. Ale o kodzie spowodował błąd: 'B' : is not a class or namespace name. (Używam Visual C++ 2005)

Odpowiedz

14

Spróbuj umieścić definicję B przed użytkownika:

class A; // forward declaration of A needed by B 

class B 
{ 
public: 
    // if these require full definition of A, then put body in implementation file 
    void fB(A& a); // Note: no body, unlike original. 
    void fB2(A& a); // no body. 
}; 

class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 

A potrzebuje pełna definicja B. Jednak B musi wiedzieć o A, ale nie potrzebuje pełnej definicji, więc potrzebujesz deklaracji forward z A.

+0

Ale jeśli w fB (A & A) używam dostęp do zmiennej w na przykład a.variable; byłoby to nielegalne, ponieważ A nie zostało jeszcze zdefiniowane. – ipkiss

+1

@ipkiss tak, ponieważ wtedy potrzebowałbyś pełnej definicji, jeśli to w deklaracji klasy nagłówka. Ale jeśli zrobiłeś to w oddzielnym pliku implementacyjnym, możesz dołączyć pełną deklarację A. – juanchopanza

2

Aby to działało, pełna definicja B musi być znana przed definicją A.

Więc naprzód zadeklarować A, ponieważ B nie potrzebuje pełnej typ i przełączyć definicje wokół:

class A; 
class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 
class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 
0

najpierw forward deklaruje klasę A, tak aby była widoczna w definicji klasy B. następnie zdefiniuj klasę A zawierającą funkcję znajomego z klasy B.

0

Przed użyciem konkretnej nazwy klasy należy ją najpierw zadeklarować. Tak więc będziesz potrzebował deklaracji klasy B, jak używasz jej w klasie A, zanim klasa B zostanie pierwotnie zadeklarowana.

Po drugie, musisz zdefiniować funkcje (które wykorzystują zmienne z obu klas - tutaj funkcje znajomego) po zdefiniowaniu obu klas. W przeciwnym razie możemy napotkać błędy.

Na przykład

#include<iostream> 

using namespace std; 

class alpha1; 

class alpha2 
{ 
    public: 

     void put_bata(int a,int b); 
}; 

void alpha2 :: put_bata(int a,int b) 
{ 
    alpha1 net; 

    net.roll=a; 

    net.id=b; 

    net.get_data(); 
} 

class alpha1 
{ 
    int roll; 

    int id; 

    public: 

     void get_data(void) 
     { 
      cout<<roll<<endl<<id<<endl; 
     } 

     friend void alpha2 :: put_bata(int a,int b); 
}; 

int main() 
{ 
    alpha2 gamma; 

    gamma.put_bata(5,6); 

    return 0; 
} 

pokaże nam błędy jako put_bata próbuje uzyskać dostęp do rolki i id, zanim zostaną one zdefiniowane nawet jeśli mieliśmy do przodu deklarację klasy ale kod podany poniżej będzie po prostu działać.

#include<iostream> 

using namespace std; 

class alpha1; 

class alpha2 
{ 
    public: 

     void put_bata(int a,int b); 
}; 

class alpha1 
{ 
    int roll; 

    int id; 

    public: 

     void get_data(void) 
     { 
      cout<<roll<<endl<<id<<endl; 
     } 

     friend void alpha2 :: put_bata(int a,int b); 
}; 

void alpha2 :: put_bata(int a,int b) 
{ 
    alpha1 net; 

    net.roll=a; 

    net.id=b; 

    net.get_data(); 
} 


int main() 
{ 
    alpha2 gamma; 

    gamma.put_bata(5,6); 

    return 0; 
} 
0

@juanchopanza @ipkiss Odnośnie problemu, że nie można uzyskać dostęp do danych na poziomie członków wewnątrz fB (A & a), ponieważ nie jest jeszcze określona. Zamiast definiowania go w oddzielnym pliku i włączania go, można po prostu zdefiniować funkcję fB (A & a) po definicji klasy A, aby fB (A & a) mógł zobaczyć elementy danych A.

2

Gdy kompilator rozpoczyna odczytanie kodu (zwykle od góry) i napotka tę linię:

friend void B::fB(A& a);

Następnie kompilator nie rozumiem co masz na myśli przez to B::. Nawet jeśli zdefiniowałeś tę klasę później w kodzie, ale kompilator tego nie wie.Zwykle dobrze jest wykonywać dalej deklarację klasy (class Name;), jeśli definicja znajduje się później w kodzie.

2

Gdy kompilator rozpoczyna kompilacji kodu (zwykle od góry) i napotka tę linię:

friend void B::fB(A& a); 
  1. w tym momencie, kompilator nie ma pojęcia o informacji typu B więc zgłasza błąd ("B": nie jest nazwą klasy lub przestrzeni nazw).
  2. przez deklarację klasy B, kompilator wie o typie B jest klasą z wyprzedzeniem do faktycznej deklaracji ze wszystkimi członkami.

  3. bieg poniżej kod do przodu po deklaracji klasy B.

///////////////

class B; 
class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){}; 
}; 
class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 

Still błędu !!!

ponieważ deklaracja przekazania jest tylko deklaracją identyfikatora, którego programista nie podał jeszcze pełnej definicji. więc kompilator potrzebuje pełnej definicji B przed klasą A.

Uwaga: definicja klasy A zależy od typu B, a także od definicji B (tj. B :: fB), więc sama deklaracja przekazania nie może zostać rozstrzygnięta, pełna definicja klasy B musi zdefiniować zanim klasy A.

4 uruchomić ten kod

////////

class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 
class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 

Wciąż błąd !!!

ponieważ funkcje składowe klasy B fB & fB2 mając argumentów typu A, ale kompilator nie ma pojęcia o informacje o typ tak przez przodu deklaracji klasy A, możemy pozwolić kompilator wie o informacje typu A. Uwaga: klasa definicja B zależy tylko od rodzaju NOT członków A tak, że przód deklaracji krok resolve 4.

  1. ostateczny kod

////// //////////////////

class A; // forward declaration of A needed by B 
class B 
{ 
public: 
    void fB(A& a); 
}; 

class A 
{ 
    int i; 
public: 
    friend void fA(A& a); //specifying function fA as a friend of A, fA is not member function of A 
    friend void B::fB(A& a); //specifying B class member function fB as a friend of A 
}; 

// fA is Friend function of A 
void fA(A& a) 
{ 
    a.i = 11; // accessing and modifying Class A private member i 
    cout<<a.i<<endl; 
} 

// B::fB should be defined after class A definition only because this member function can access Class A members 
void B::fB(A& a) 
{ 
    a.i = 22; // accessing and modifying Class A private member i in Class B member function fB 
    cout<<a.i<<endl; 
} 

int main() 
{ 
    A a; 
    fA(a); // calling friend function of class A 

    B b; 
    b.fB(a); // calling B class member function fB, B:fB is friend of class A 

    return 0; 
} 

6 Ćwiczenie:

// Cyclic dependency 
#include<iostream> 
using namespace std; 

class A; 

class B 
{ 
public: 
    void fB(A& a); 
    friend void A::fA(B& b); //specifying class A's member function fA as a friend of B 
}; 

class A 
{ 
    int i; 
public: 
    void fA(B& b); 
    friend void B::fB(A& a); //specifying class B's member function fB as a friend of A 
}; 

int main() 
{ 
    return 0; 
} 
+0

. Jak rozwiązać ćwiczenie? –

+0

@BrunoMartinez - Nie ma na to idealnego rozwiązania, ponieważ oba są cyklicznie zależne od siebie nawzajem. Moją intencją było, aby ten szczególny przypadek podkreślał znaczenie oddzielenia podmiotów w projektowaniu oprogramowania i uzyskania większej przejrzystości w funkcji Przyjaciela podczas pracy nad tym. Chyba już wiesz, że możliwą opcją jest utworzenie wspólnej funkcji znajomego – SrinivasPaladugu

Powiązane problemy