我有一种情况,我想隐藏基类并限制可以从中继承的类:
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
编译器告诉我,_detail::Private::Base
,A
和B
无法访问C
,即使他们是Private
的朋友。我之前使用过这种模式没有问题,而且与其他时候使用它相比,我无法真正看到这里有什么不同。我没看到什么?
答案 0 :(得分:3)
C ++语言不允许您在好友声明中使用限定名称(如::A
),除非这些限定名称引用以前声明的实体。实际上,这条规则适用于所有地方,不仅适用于朋友声明:限定名称必须引用先前声明的实体。
在您的情况下,您在朋友声明::A
中使用了限定名friend struct ::A
。为了实现这一点,必须事先为编译器知道全局命名空间中的struct A
。在您的情况下,A
未在此时声明,这使得friend struct ::A
声明格式不正确。它甚至不应该通过正式的语言规则进行编译。
如果你的编译器接受了这个,你必须查阅你的编译器文档来弄清楚它的含义。我怀疑未知friend struct ::A
的{{1}}被解释为等同于::A
,即它将friend struct A
声明为朋友。
如果在声明命名空间_detail::A
之前发出前向声明struct A;
,它可能会使其按预期工作。