26
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?

Columbo
  • 60,038
  • 8
  • 155
  • 203
Smatik
  • 407
  • 5
  • 15
  • 1
    possible duplicate of [Friend declaration in C++ - difference between public and private](http://stackoverflow.com/questions/6407691/friend-declaration-in-c-difference-between-public-and-private) – ha9u63a7 Nov 16 '14 at 11:05
  • 10
    @hagubear Definitely not a duplicate of that. –  Nov 16 '14 at 11:05
  • Are you asking why the language doesn't allow this? At some point someone thought (understandably) that this would be a bad idea. – juanchopanza Nov 16 '14 at 11:10
  • 2
    Because otherwise it wouldn't be private. – user207421 Nov 16 '14 at 11:21

2 Answers2

18

[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.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Maybe I don't understand the question, but shouldn't it be the opposite way, that is, make `y` friend of `x`? In your example `y` wouldn't get access to private methods of `x`. – Ivan Smirnov Oct 27 '17 at 20:10
  • 1
    @IvanSmirnov The intention of the original snippet was to permit a member of `x` to access private data of `y`. – Columbo Oct 27 '17 at 20:11
  • Ah, right, not the most intuitive thing. Thanks, got it. – Ivan Smirnov Oct 27 '17 at 20:12
  • @IvanSmirnov What you suggest is hvd's approach below, which appears to be needlessly convoluted. – Columbo Oct 27 '17 at 20:14
16

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.)

  • I can have a virtual member function that is private and overridden in a subclass. Renaming that virtual function in the base class would break something, wouldn't it?` – Columbo Nov 16 '14 at 11:20
  • 1
    I like the distinction of what question *exactly* you are answering. – Peter - Reinstate Monica Nov 16 '14 at 11:22
  • @Columbo You're right. That's one of the differences between "it means" and "it should mean". :) –  Nov 16 '14 at 11:25
  • Btw. your approach of resolving this is odd. Make an entire class `y` a friend of `x` for it *to be able to befriend a member of `x`*? Why the detour? – Columbo Oct 27 '17 at 20:17
  • @Columbo It depends on the concrete case. Usually, sure, just make all of `x` a friend of `y`. This is the obvious solution. But if `x` is a huge class with lots of functions and `y` is a tiny helper class, making `y` and `x::xx` friends can be far less invasive than making all of `x` a friend. –  Oct 27 '17 at 20:45
  • @hvd Sure, if your metric of invasion is how much is invaded, not by how many :-) I agree on the idea, however. – Columbo Oct 27 '17 at 21:45