I have a situation where I want to hide a base class and limit the classes that can inherit from it:
namespace _detail {
class Private abstract final {
struct Base abstract {
protected:
Base() {}
};
friend struct ::A;
friend struct ::B;
friend struct ::C;
};
}
struct A : _detail::Private::Base {}; //error
struct B : _detail::Private::Base {}; //error
struct C : _detail::Private::Base {}; //error
The compiler tells me that _detail::Private::Base
is inaccessible to A
, B
and C
even though they are friends with Private
. I've used this sort of pattern before without an issue, and can't really see what's different here compared to the other times I've used it. What am I not seeing?
C++ language does not allow you to use qualified names (like ::A
) in friend declarations, unless these qualified names refer to previously declared entities. Actually, this rule is applied virtualy everywhere, not only in friend declarations: qualified names have to refer to previously declared entities.
In your case you used qualified name ::A
in friend declaration friend struct ::A
. For that to work, struct A
from global namespace has to be known to the compiler beforehand. In your case A
is not declared at that point, which makes friend struct ::A
declaration ill-formed. It should not even compile by formal rules of the language.
If your compiler accepts this, you have to consult your compiler documentatuion to figure out what it means. I suspect that friend struct ::A
for unknown ::A
is interpreted as equivalent to friend struct A
, i.e. it declares _detail::A
as friend.
If you make a forward declaration struct A;
before declaring namespace _detail
, it might make it work as intended.