Funcții și clase prietene
Funcțiile prietene sunt funcții care nu sunt membre ale clasei, însă au acces la membrii săi privați – variabilele și funcțiile declarate cu specificatorul private.
Pentru definirea funcțiilor prietene se folosește cuvântul cheie friend. De exemplu, să definim următorul program:
#include <iostream>
class Auto
{
friend void drive(const Auto&);
friend void setPrice(Auto&, unsigned);
public:
Auto(std::string autoName, unsigned autoPrice)
{
name = autoName;
price = autoPrice;
}
void print()
{
std::cout << name << " : " << price << std::endl;
}
private:
std::string name; // denumirea automobilului
unsigned price; // prețul automobilului
};
void drive(const Auto &car)
{
std::cout << car.name << " is driven" << std::endl;
}
void setPrice(Auto &car, unsigned price)
{
car.price = price;
}
int main()
{
Auto tesla("Tesla", 5000);
tesla.print(); //
drive(tesla);
setPrice(tesla, 8000);
tesla.print(); //
}
Aici este definită clasa Auto, care reprezintă un automobil. Această clasă are variabile private name (denumirea automobilului) și price (prețul automobilului). De asemenea, în clasă sunt declarate două funcții prietene: drive (funcție pentru conducerea automobilului) și setPrice (funcție pentru stabilirea prețului). Ambele funcții primesc ca parametru o referință la un obiect de tip Auto.
Când declarăm funcții prietene, practic îi spunem compilatorului că acestea sunt prietene ale clasei și au acces la toți membrii acesteia, inclusiv cei privați.
În același timp, pentru funcțiile prietene nu contează dacă sunt declarate sub specificatorul public sau private. Pentru ele acest lucru nu are importanță.
Definirea acestor funcții se face în afara clasei. Și, deoarece aceste funcții sunt prietene, putem accesa în interiorul lor toate variabilele private ale clasei Auto prin referința transmisă.
Ieșirea în consolă a programului:
Tesla : 5000
Tesla is driven
Tesla : 8000
Definirea funcțiilor prietene într-o altă clasă
Funcțiile prietene pot fi definite într-o altă clasă. De exemplu, să definim clasa Person, care folosește obiectul Auto:
#include <iostream>
class Auto; // declarația clasei Auto pentru ca Person să o vadă
class Person
{
public:
Person(std::string p_name)
{
name = p_name;
}
void drive(const Auto&);
void setPrice(Auto&, unsigned);
private:
std::string name;
};
class Auto
{
// declararea funcțiilor prietene
friend void Person::drive(const Auto&);
friend void Person::setPrice(Auto&, unsigned);
public:
Auto(std::string a_name, unsigned a_price)
{
name = a_name;
price = a_price;
}
void print()
{
std::cout << name << " : " << price << std::endl;
}
private:
std::string name; // denumirea automobilului
unsigned price; // prețul automobilului
};
void Person::drive(const Auto &car)
{
std::cout << name << " drives " << car.name << std::endl;
}
void Person::setPrice(Auto &car, unsigned price)
{
car.price = price;
}
int main()
{
Auto tesla{"Tesla", 5000};
Person tom{"Tom"};
tom.drive(tesla);
tom.setPrice(tesla, 8000);
tesla.print();
}
La început este definită clasa Person, care reprezintă o persoană. Însă, deoarece clasa Person folosește clasa Auto, înainte de Person este plasată declarația clasei Auto.
Două funcții din clasa Person primesc o referință la un obiect Auto:
void drive(const Auto&);
void setPrice(Auto&, unsigned);
Adică, figurativ vorbind, o persoană conduce un automobil și îi setează prețul prin aceste funcții.
Clasa Auto declară funcțiile prietene cu aceeași semnătură:
friend void Person::drive(Auto&);
friend void Person::setPrice(Auto&, unsigned);
Și, deoarece aceste funcții sunt definite în clasa Person, numele lor este prefixat cu Person: :
Deoarece în aceste funcții se va folosi obiectul Auto, toate membrele obiectului Auto trebuie să fie cunoscute în momentul definirii acestor funcții, de aceea definirea funcțiilor nu se face în interiorul clasei Person, ci după clasa Auto. Și, deoarece aceste funcții sunt declarate ca prietene în clasa Auto, putem accesa în interiorul lor membrii privați ai clasei Auto.
Ieșirea în consolă a programului:
Tom drives Tesla
Tesla : 8000
Clase prietene
În exemplul anterior, clasa Person folosește doar două funcții din clasa Auto. Dar, să presupunem că ulterior apare necesitatea de a adăuga în clasa Auto și alte funcții prietene care vor fi definite în clasa Person. Sau putem presupune că Person va lucra activ cu obiecte de tip Auto. În acest caz, este mai rațional să definim întreaga clasă Person ca prietenă, în loc de funcții separate:
#include <iostream>
class Auto; // declarația clasei Auto pentru ca Person să o vadă
class Person
{
public:
Person(std::string p_name)
{
name = p_name;
}
void drive(const Auto&);
void setPrice(Auto&, unsigned);
private:
std::string name;
};
class Auto
{
// declararea clasei prietene
friend class Person;
public:
Auto(std::string a_name, unsigned a_price)
{
name = a_name;
price = a_price;
}
void print()
{
std::cout << name << " : " << price << std::endl;
}
private:
std::string name; // denumirea automobilului
unsigned price; // prețul automobilului
};
void Person::drive(const Auto& car)
{
std::cout << name << " drives " << car.name << std::endl;
}
void Person::setPrice(Auto& car, unsigned price)
{
car.price = price;
}
int main()
{
Auto tesla{"Tesla", 5000};
Person tom{"Tom"};
tom.drive(tesla);
tom.setPrice(tesla, 8000);
tesla.print();
}
Singurul lucru care s-a schimbat în comparație cu exemplul precedent este faptul că în clasa Auto definirea funcțiilor prietene a fost înlocuită cu definirea unei clase prietene:
friend class Person;
Adică, astfel spunem din nou că clasa Person este prietenă a clasei Auto, și de aceea obiectele Person pot accesa membrii privați ai clasei Auto. După aceasta, din orice funcție a clasei Person se poate accesa membrii privați ai clasei Auto.