[My original answer was nonsense. Apologies for that. Thank you to @celtschk for pointing that out and providing the better answer.]
If C
is a friend of B
, it can access all of B
's members, whether private, public, or protected, and that includes the accessible (public and protected) members that are part of a base subobject:
struct A { protected: int a; };
struct B : A { private: int b; friend struct C; }
struct C
{
B x;
A w;
void f()
{
x.a = 1; // fine
x.b = 2; // fine
// w.a = 0; /* Error, #1 */
}
friend struct D; // see below
};
However, friendship is neither transitive nor inherited: C
is a friend of B
, but not of A
(see #1). Also, if D
is a friend of C
, then D
doesn't get any of the access that C
's friendship to B
affords it, so D
cannot access B
's non-public members. Similarly, if struct E : C
inherits from C
, then E
is also not a friend of B
automatically:
struct D
{
B y;
void g()
{
// y.b = 3; /* Error! */
}
};
struct E : C
{
B z;
void h()
{
// y.b = 4; /* Error! */
}
}
Perhaps one can summarize what's going on in a few points:
A derived class has access to all public and protected members of each base class.
A friend of a class has access to all members of that class that are accessible to it (i.e. all members excluding private base members).
Friendship is not inherited: If a class has a friend, that friendship does not apply to any of its base classes nor to any of its derived classes.
A friend of a friend is not a friend.