Something Y needs to be declared a friend of X by X itself, otherwise we would break encapsulation very easily.
A friend statement is a forward reference and convention is to put them at the start of the class definition.
We should be wary about overusing friend functions, or friend classes, but using friends appropriately can strengthen encapsulation by allowing data to remain private except when we really need it to be accessed directly.
class A {
friend class B;
int a;
};
class B {
void func(A &p) { p.a = 1; }
};
Friendship is not transitive. So, in the example below, C is not a friend of A.
class A {
friend class B;
int a;
};
class B {
friend class C;
};
class C {
void func(A &p){ p.a = 1; }
};