[ azzpoz @ 19.11.2013. 18:06 ] @
Interesuje me kada postavljati ampersand i zbog čega???

npr.

class tacka s parametrima A i B

Code:
friend tacka operator+(tacka &, tacka &);

tacka operator+(tacka &lijevo, tacka &desno){...}


Code:
tacka &operator+=(tacka &);

tacka &tacka::operator+=(tacka &desno){...}


Da li amperand koristimo samo kada (originalni/lijevi) parameretar kojeg želimo promijeniti treba biti pozvan u originalnom obliku?!
[ djoka_l @ 19.11.2013. 18:17 ] @
http://www.cplusplus.com/doc/tutorial/functions2/

Sa ampersandom varijable se šalju po referenci (passing value by reference) umesto po vrednosti (by value). To znači da se funkciji predaje pokazivač na sadržaj umesto kopije sadržaja. Ovo je bitno ako pozivajuća funkcija treba da izmeni vredost varijable ili da se izbegne overhed kopiranja vrednosti.
[ azzpoz @ 19.11.2013. 18:25 ] @
Ako sam dobro razumio, moje "razmišljanje" je ok, tj. ako želimo osigurati da originalnu varijablu mjenjamo, definišemo s ampersandom &operator+=(u ovom slučaju lijevi objekat, nad kojim se treba izvršiti izmjena)?!


Mene je samo interesovalo da li je zbog toga pri definiciji preklapanja operatora, korišten ampersand (&) ispred operator+=
[ djoka_l @ 19.11.2013. 18:42 ] @
Ne, kod deklaracije funkcije (operatora) & znači da operator vraća pokazivač.

Recimo, operator uradi new (alocira prostor za objekt tipa "tacka"), i vraća referencu na tu lokaciju.

Uzgred, zaboravi na friend funkcije. Da bih ti pomogao u tome, obećavam ti da ti neću odgovoriti više ni na jedno pitanje, ako u tekstu, ili kodu upotrebiš firend.
[ azzpoz @ 19.11.2013. 18:59 ] @
Zar to nije neophodno za pristup članovima objekta klase, ako je u pitanju globalna funkcija?!
[ djoka_l @ 19.11.2013. 19:15 ] @
To je potrebno za pristup protected ili private članovima klase, a vrlo je loše da se koristi jer narušava koncept enkapsulacije. Ako je nešto private ili protected, postoje dobri razlozi za to, a friend to narušava.
U tvom slučaju, to je jako loše, nauči da programiraš kako treba. Ako treba da pristupiš članovim klase, neka i funkcija bude član klase.
[ Burgos @ 19.11.2013. 19:21 ] @
djoka_l, nisi u pravu - npr., ukoliko ne možeš da preklopiš binarni operator koristeći javni interfejs, nema ništa loše u tome da je postaviš kao friend funkciju - za to friend i služi (koliko vidim azzpoz je baš u tom kontekstu i upotrebio friend deklaraciju). "Ako treba da pristupiš članovima klase, neka i funkcija bude član klase" ne stoji kod preklapanja operatora<< ili operatora>> ili operatora gde je potrebno da dozvoliš konverziju tipova levog operanda (azzpoz je baš imao taj primer u nekom prethodnom pitanju).


Evo jednog sjajnog Skotovog članka upravo o tome:


How Non-Member Functions Improve Encapsulation

Citat:
Just like member functions, friend functions may be broken when a class's implementation changes, so the choice between member functions and friend functions is properly made on behavioral grounds. Furthermore, we now see that the common claim that "friend functions violate encapsulation" is not quite true. Friends don't violate encapsulation, they just decrease it — in exactly the same manner as member functions.
[ glorius @ 20.11.2013. 08:35 ] @
I ja se ne slazem sa djoka_I.

Evo primera gde Non-Member friend funkcije mogu da pomognu:

Recimo da imamo klasu koja ima int kao member i zelimo da sabiramo tu klasu sa obicnom int promenljivom:

Code:


class SomeClass
{
    int m_data;
public:
    SomeClass(int data) : m_data(data) {}

        // za slucaj 1. u main()
    SomeClass operator+(int rhs)
    {
        return SomeClass(m_data + rhs);
    }
 
        // da bi slucaj 2. u main() radio moramo da implementiramo operator int()
        /*
    operator int() const
    {
        return m_data;
    }
        */
};

int main()
{
    SomeClass a(3);
    SomeClass b = a + 3;    ..... 1.
    SomeClass c = 3 + a;    ..... 2.       
        return 0;
}



Po meni, bolji nacin za ovo je:

Code:


class SomeClass
{
    int m_data;
public:
    SomeClass(int data) : m_data(data) {}

    // ova funkcija moze da ostane kao u proslom primeru ali cu i nju napisati kao friend
    friend SomeClass operator+(const SomeClass& sc, int a);
      
    friend SomeClass operator+(int a, const SomeClass& sc);
};

SomeClass operator+(const SomeClass& sc, int a)
{
    return SomeClass(sc.m_data + a);
}

SomeClass operator+(int a, const SomeClass& sc)
{
    return SomeClass(sc.m_data + a);
}

int main()
{
    SomeClass a(3);
    SomeClass b = a + 3;
    SomeClass c = 3 + a;
        return 0;
}



Istina je da se ovim narusava enkapsulacija. Kod se moze poboljsati tako sto se moze obezbediti get() metoda za m_data i da se poziva getter umesto direktnog pristupa m_data promenljivoj u operator+() funkcijama ali ne mislim da je ovo losa praksa programiranja ako se primenjuje u prikladnim situacijama kao sto je ovaj primer.

Evo jos jednog primera.

Ako imamo klasu Element i iz nje izvedene Line, Circle itd. i zelimo da napravimo ogranicen mehanizam za kreaciju ovih objekata, u smislu da user ne moze direktno da pozove new za Line, Circle vec mora da koristi Factory, na primer, zato sto je za kreaciju objekta potrebno vise koraka koji se striktno moraju odraditi a ne zelimo da opteretimo klijenta ovih klasa tim detaljima, tada mozemo da stavimo da su konstruktori Line, Circle privatni a da Factory klasa bude friend klasama Line i Circle tako da samo Factory moze da pozove konstruktore klasa Line i Circle.

Advanced: Konkretna potreba za ovim bi bila u slucaju da se koristi shared_from_this() funkcija koja ne moze da se pozove dok objekat nije potpuno konstruisan pa posle toga mora da se pozove neka init() funkcija koja bi pozvala shared_from_this() da bi objekat, na primer, sam sebe dodao u neku listu. Ili u Qt, posle konstruisanja objekta da se objekat poveze pomocu signala/slotova sa drugim objektima.

[Ovu poruku je menjao glorius dana 20.11.2013. u 10:49 GMT+1]
[ Burgos @ 21.11.2013. 10:01 ] @
Citat:
Istina je da se ovim narusava enkapsulacija. Kod se moze poboljsati tako sto se moze obezbediti get() metoda za m_data i da se poziva getter umesto direktnog pristupa m_data promenljivoj u operator+() funkcijama ali ne mislim da je ovo losa praksa programiranja ako se primenjuje u prikladnim situacijama kao sto je ovaj primer.


Nije loša praksa, jer pisanjem javne getter funkcije za m_data bespotrebno eksponiraš privatni član klase preko javnog interfejsa - ako nema razloga da klijent ikada dobije ovu vrednost direktno, nema razloga ni za pisanjem getter metode - tako upravo narušavaš enkapsulaciju. Telo friend ili non-member funkcije se može napisati u istom cpp fajlu gde je napisana implementacija klase, pa se klijent nikada ne mora upoznati sa implementacijom - za mene, kao korisnika klase, nije bitno da li je neka funkcija friend, non-member ili member - bitno je da je mogu koristiti smisleno, i za mene ona predstavlja deo interfejsa. Pravi primeri su std::getline, std::stoi i druge non-member metode iz zaglavlja <string>.