Za Sephiroth?-a:
Evo mali isjecak iz jedne knjige o friend funkcijama:
Razmotrimo definicije preopterecenih operatora jedanosti za klasu String koji su definisani u oblasti vazenja prostora imena. Operator jednakosti za dva objekta klase string je:
Code:
bool operator==(const String &str1, const String str2)
{
if( str1.size() != str2.size() )
return false;
return strcmp( str1.c_str(), str2.c_str() ) ? false : true;
}
Uporedite ovu definiciju sa definicijom istog operatora kada je on definisan kao funkcija clanica:
Code:
bool String::operator==(const String &rhs ) const
{
if( _size != rhs.size() )
return false;
return strcmp( _string, shs._string ) ? false : true;
}
Da li vidite razliku? Uocite da smo u ovoj definiciji morali da promenimo nacin na koji se koriste privatni podaci clanovi klase String. Posto je novi operator jednakosti globalna funkcija, a ne funkcija clanica klase, on ne moze da direktno koristi privatne podatke clanove klase String. Zbog toga, za dobijanje velicine objekta klase String i njemu odgovarajuce niske znakova u stilu jezika C, on koristi pristupne funkcije clanice size() i c_str();
Drugo moguce resenje je da se ovi globalni operatori jednakosti deklarisu kao prijatelji klase String. Ako neka klasa deklarise funkciju ili operator kao prijatelje, ona toj funkciji ili operatoru daje pravo pristupa do svojih nejavnih clanova.
Deklaracija prijatelja pocinje kljucnom reci friend. Ona moze da se nalazi samo unutar definicije klase. Posto prijatelji nisu clanovi klase koja proglasava prijateljstvo, na njih ne utice to da li su unutar tela klase deklarisani u javnoj, privatnoj ili zasticenoj sekciji. U sledecem primeru izabrali smo da sve deklaracije prijatelja grupisemo odmah posle zaglavlja klase:
Code:
class String{
friend bool operator==(const String &, const String &);
friend bool operator==(const char *, const char *);
friend bool operator==(const String &, const char *);
public:
//...ostatak klase String
};
Ove tri deklaracije prijatelja u klasi String deklarisu tri preopterecena operatora poredjenja koja su deklarisana u globalnoj oblasti vazenja kao prijatelji klase String.
Sada posto su operatori jednakosti deklarisani kao prijatelji, njihova definicija moze da direktno koristi privatne clanove klse String:
Code:
// operatori koji su prijatelji: mogu da direktno koriste privatne clanove klse String
bool operator==(const String &str1, const String &str2)
{
if( str1._size() != str2._size() )
return false;
return strcmp( str1._string(), str2._string() ) ? false : true;
}
inline bool operator==(const String &str1, const char *s)
{
return strcmp( str._string, s ) ? false : true;
}
Neko moze sa pravom da tvrdi da, u ovom slucaju, direktan pristup clanovima _size i _string nije neophodan, posto funkcije size() i c_str(), kao umetnute, daju jednaku efikasnost, a u isto vrijeme obezbedjuju i enkapsulaciju podataka clanova. Koriscenje pristupnih funkcija umjesto direktnog pristupa clanovima ne znaci uvjek i manje efikasnu imeplementaciju. Zbog ovih pristupnih funkcija nema potrebe da deklariseno operatore jednakosti kao funkcije prijaljtelje klase String.
Kako se onda odlucujemo da li neki operator koji nije clan klase treba da bude proglasen prijteljem ili in treba da koristi pristupne funkcije clanice? U opstem slucaju dizajner klase treba da tezi da minimizuje broj globalnih funkcija i operatora koji imaju pristup do interne reprezentacije klase. Ako postoje funkcije za pristup clanovima koje su jednako efikasne, onda je bolje da se one koriste i time izoluju globalni operatori od promjena u reprezentaciji klase, bas kao sto se to radi sa drugim funkcijama prostora imena. Ako za neke privatne clanove klase ne postoje odgovarajuce pristupne funkcije u lasi, i ako globalni operatori za obavljanje svojih funkcija moraju da koriste te privatne clanove, onda koriscenjem mehanizma prijatelja postaje neophodno.
Najcesca primjena mehanizma prijatelja je da se preopterecenom operatoru koji nije clan klase dozvoli pristup do privatnih clanova te klase ciji je on prijatelj. Razlog za ovo, pored potrebe da se omoguci simetrija koriscenja levog i desnog operanda, jeste sto bi preopterecen operator i inace morao da bude funkcija sa punim pristupom do privatnih clanova klase.
Mada je dominantna primjena mehanizma prijatelja ona za preopterecene operatore, postoje slucajevi kada funkcija prostora imena, funkcija clanica neke druge prethodno definisane klase ili citava klasa moraju da se deklarisu kao prijatelji. Kada se jedna klasa proglasava prijateljem druge, funkcije clanice klasa prijatelja dobijaju pristup do nejavnih clanova klase koja proglasava prijateljstvo. Sada cemo deteljnije razmotriti deklaracije prijatelja za funkcije koje nisu operatori.
Klasa mora da deklarise kao prijatelja svaku funkciju iz skupa preopterecenih funkcija koje zeli da ucini prijateljima. Na primjer:
Code:
extern ostream& storeOn( ostream &, Screen & );
extern BitMap& storeOn( BitMap &, Screen & );
//...
class Screen {
extern ostream& storeOn( ostream &, Screen & );
extern BitMap& storeOn( BitMap &, Screen & );
//...
};
Ako funkcija manipulise objektima dvije razlicite klase i potreban joj je pristup do nejavnih clanova obe klase, ta funkcija moze bilo da se deklarise obe klase, bilo da se ucini funkcijom clanicom jedne a prijateljem druge...
Primjer:
Ako odlucimo da funkcija mora da bude prijatelj obe klase, ove deklaracije prijateljstva izgledaju kao na primjer:
Code:
class Window;//samo deklaracija
class Screen {
friend bool is_equal ( Screen &, Window & );
/...
};
class Window {
friend bool is_equal ( Screen &, Window & );
/...
};
Ako odlucimo da funkcija mora da bude clanica jedne klase a prijatelj druge klase, deklaracija funkcije clanice i deklaracija prijatelja su na primjer:
Code:
class Window;
class Screen {
public:
// copy je funkcija clanica klase Screen
Screen& copy ( Window & );
//...
};
class Window {
// Screen::copy je prijatelj klase Window
friend Screen& Screen::copy( Window & );
// ...
};
Screen& Screen::copy( Window & ) { /* ... */ }
Funkcija clanica neke klase ne moze da se deklarise kao prijatelj druge klase pre definicije ove prve klase. ovo se ne moze uvjek postici. Na primjer, sta ako klasa Screen mora kao prijatelje da deklarise funkcije clanice klase Window, a klasa Window isto mora kao prijatelje da deklarise funkcije clanice klase Screen? U ovom slucaju, citava klasa Window moze da se deklarise kao prijatelj klase Screen. Na primjer:
Code:
class Window;
class Screen {
friend class Window;
/...
};
Svaka funkcija clanica klase Window sada ima pristup svim ne javnim clanovima klase Screen;
Nadam se da sam pomogao, i da ces uspjeti da shvatis svrhu friend. Ako nesto jos treba javi...
Pozdrav