Why can't a PRIVATE member function be a friend function of another class?

8.7k views Asked by At
class x
{
    void xx() {}
};

class y
{
    friend void x::xx();
};

This results in an error like

error: friend function 'xx' is a private member of 'x'

Why can't I declare a private member function to be a friend of another class?

2

There are 2 answers

4
Columbo On BEST ANSWER

[class.friend]/9:

A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration.

The reason is quite simple; private members shall obey a clear and definite rule:

A member of a class can be

  • private; that is, its name can be used only by members and friends of the class in which it is declared.

Allowing private members to be named in declarations inside unrelated classes would violate this rule: it enables another class to depend on an implementation detail without being explicitly allowed to. This becomes problematic, for instance, when changing a private member's name, type or signature, or removing it entirely; that's intended not to break the interface of that class.

This can be circumvented by making the entirety of x a friend of y:

class x {
    void xx() {}
};

class y {
    friend x;
};

Demo.

6
AudioBubble On

The idea of making x::xx private is supposed to be that x::xx is an implementation detail that other classes should not be relying on. It doesn't just mean that x::xx cannot be called by other classes, it means, or rather it should mean, that e.g. renaming x::xx to x::xy shouldn't break anything other than the class itself, and the class's friends.

In your case, renaming x::xx to x::xy would cause class y to have an error, even though it is not a friend of x.

A way to avoid that is to make y a friend of x, so that y can access x's private members. It can then declare x::xx as a friend.

(Note: the more direct answer to the question "Why does the compiler not allow this?" is "Because the standard does not allow this.", which naturally leads to the follow-up question "Why does the standard not allow this?". I'm attempting to answer that follow-up question.)