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

2

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?

Threlkeld answered 16/11, 2014 at 10:56 Comment(4)
possible duplicate of Friend declaration in C++ - difference between public and privateFuthark
@hagubear Definitely not a duplicate of that.Handmedown
Are you asking why the language doesn't allow this? At some point someone thought (understandably) that this would be a bad idea.Rely
Because otherwise it wouldn't be private.Michelsen
O
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.

Ode answered 16/11, 2014 at 11:10 Comment(4)
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.Adios
@IvanSmirnov The intention of the original snippet was to permit a member of x to access private data of y.Ode
Ah, right, not the most intuitive thing. Thanks, got it.Adios
@IvanSmirnov What you suggest is hvd's approach below, which appears to be needlessly convoluted.Ode
H
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.)

Handmedown answered 16/11, 2014 at 11:13 Comment(6)
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?`Ode
I like the distinction of what question exactly you are answering.Andreas
@Ode You're right. That's one of the differences between "it means" and "it should mean". :)Handmedown
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?Ode
@Ode 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.Handmedown
@hvd Sure, if your metric of invasion is how much is invaded, not by how many :-) I agree on the idea, however.Ode

© 2022 - 2024 — McMap. All rights reserved.