A class or a structure may declare any function it's friend. If a function is a friend of a class, it may access all it's protected and private members:
// 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;
}
Access modifiers do not alter friend semantics. Public, protected and private declarations of a friend are equivalent.
Friend declarations are not inherited. For example, if we subclass PrivateHolder
:
class PrivateHolderDerived : public PrivateHolder {
public:
PrivateHolderDerived(int val) : PrivateHolder(val) {}
private:
int derived_private_value = 0;
};
and try to access it's members, we'll get the following:
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;
}
Note that PrivateHolderDerived
member function cannot access PrivateHolder::private_value
, while friend function can do it.
Methods may declared as friends as well as functions:
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;
}
A whole class may be declared as friend. Friend class declaration means that any member of the friend may access private and protected members of the declaring class:
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;
}
Friend class declaration is not reflexive. If classes need private access in both directions, both of them need friend declarations.
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;
};