C++
Słowo kluczowe znajomego
Szukaj…
Wprowadzenie
Dobrze zaprojektowane klasy zawierają ich funkcjonalność, ukrywając ich implementację, zapewniając jednocześnie przejrzysty, udokumentowany interfejs. Umożliwia to przeprojektowanie lub zmianę, o ile interfejs pozostaje niezmieniony.
W bardziej złożonym scenariuszu może być wymagane wiele klas, które opierają się na wzajemnych szczegółach implementacji. Klasy i funkcje znajomych pozwalają tym rówieśnikom na dostęp do swoich danych, bez uszczerbku dla enkapsulacji i ukrywania informacji w udokumentowanym interfejsie.
Funkcja przyjaciela
Klasa lub struktura może zadeklarować dowolną funkcję, którą jest przyjacielem. Jeśli funkcja jest przyjacielem klasy, może uzyskać dostęp do wszystkich chronionych i prywatnych członków:
// Forward declaration of functions.
void friend_function();
void non_friend_function();
class PrivateHolder {
public:
PrivateHolder(int val) : private_value(val) {}
private:
int private_value;
// Declare one of the function as a friend.
friend void friend_function();
};
void non_friend_function() {
PrivateHolder ph(10);
// Compilation error: private_value is private.
std::cout << ph.private_value << std::endl;
}
void friend_function() {
// OK: friends may access private values.
PrivateHolder ph(10);
std::cout << ph.private_value << std::endl;
}
Modyfikatory dostępu nie zmieniają semantyki znajomych. Publiczne, chronione i prywatne deklaracje znajomego są równoważne.
Deklaracje znajomych nie są dziedziczone. Na przykład, jeśli PrivateHolder
:
class PrivateHolderDerived : public PrivateHolder {
public:
PrivateHolderDerived(int val) : PrivateHolder(val) {}
private:
int derived_private_value = 0;
};
i spróbuj uzyskać dostęp do jego członków, otrzymamy:
void friend_function() {
PrivateHolderDerived pd(20);
// OK.
std::cout << pd.private_value << std::endl;
// Compilation error: derived_private_value is private.
std::cout << pd.derived_private_value << std::endl;
}
Zauważ, że PrivateHolderDerived
członkowska PrivateHolderDerived
nie może uzyskać dostępu do PrivateHolder::private_value
, podczas gdy funkcja znajomego może to zrobić.
Metoda przyjaciela
Metody mogą być deklarowane jako przyjaciele, a także funkcje:
class Accesser {
public:
void private_accesser();
};
class PrivateHolder {
public:
PrivateHolder(int val) : private_value(val) {}
friend void Accesser::private_accesser();
private:
int private_value;
};
void Accesser::private_accesser() {
PrivateHolder ph(10);
// OK: this method is declares as friend.
std::cout << ph.private_value << std::endl;
}
Klasa przyjaciela
Cała klasa może zostać uznana za przyjaciela. Deklaracja klasy znajomego oznacza, że każdy członek znajomego może uzyskać dostęp do prywatnych i chronionych członków deklarującej klasy:
class Accesser {
public:
void private_accesser1();
void private_accesser2();
};
class PrivateHolder {
public:
PrivateHolder(int val) : private_value(val) {}
friend class Accesser;
private:
int private_value;
};
void Accesser::private_accesser1() {
PrivateHolder ph(10);
// OK.
std::cout << ph.private_value << std::endl;
}
void Accesser::private_accesser2() {
PrivateHolder ph(10);
// OK.
std::cout << ph.private_value + 1 << std::endl;
}
Deklaracja klasy przyjaciół nie jest zwrotna. Jeśli zajęcia potrzebują prywatnego dostępu w obu kierunkach, oba potrzebują deklaracji znajomych.
class Accesser {
public:
void private_accesser1();
void private_accesser2();
private:
int private_value = 0;
};
class PrivateHolder {
public:
PrivateHolder(int val) : private_value(val) {}
// Accesser is a friend of PrivateHolder
friend class Accesser;
void reverse_accesse() {
// but PrivateHolder cannot access Accesser's members.
Accesser a;
std::cout << a.private_value;
}
private:
int private_value;
};