C++ 声明受保护的函数友元

C++ 声明受保护的函数友元,c++,function,friend,protected,C++,Function,Friend,Protected,A::foo是否需要声明为公共的B才能声明为好友 class A { protected: // public ? void foo(int x); }; class B : public A { friend void A::foo(int); // not fine with GCC 4.8.1 but fine with VS 2013 void goo(int x) {foo(x);} // fine static void hoo

A::foo
是否需要声明为公共的
B
才能声明为好友

class A {
    protected:  // public ?
        void foo(int x);
};

class B : public A {
    friend void A::foo(int);  // not fine with GCC 4.8.1 but fine with VS 2013
    void goo(int x) {foo(x);}  // fine
    static void hoo(int x) {}
};

void A::foo(int x) {B::hoo(x);}  // friend declaration needed for this

Visual Studio 2013认为A::foo受保护是好的,但GCC 4.8.1认为不是,希望它公开。哪个编译器是正确的?我最初的直觉是可以宣布它受到保护。毕竟,B是从A派生的,所以应该可以访问A::foo(正如B::goo简单地演示的那样)。

VS在这里是正确的

名称
A::foo
实际上可以在
B
的范围内访问,因为它是从
A
公开派生的。对此,考虑

class A {
    protected:
        void foo(int x);
};

class B : A {
    using A::foo; // it's OK to refer to the name A::foo
};

void A::foo(int x) {}  
因此,通过引用§11.3[朋友函数]

友元声明指定的名称应可在包含友元声明的类的范围内访问

我们可以说没有违反规则(
foo
在派生类中也受到保护)

在gcc中,一旦将
friend
关键字放在friend函数声明前面,名称查找就会开始忽略继承(与友谊不可继承无关)



正如注释中提到的,相同的错误是从Clang发出的,并且它有一个;这个问题也被提到。对于实现者来说,似乎很难做到这一点。

如果它是公开的,就没有必要让它成为朋友。如果它受保护,在您的示例中仍然没有意义,因为您继承自
A
,因此可以访问其所有受保护的成员。@Cameron。我编辑了这篇文章,以表明需要朋友声明。当被问及iso讨论时,除了从语言律师的角度来看有趣的问题外,你认为这是一个好的设计吗?基类是否知道派生类型?那似乎有点不对劲。。。您的设计中存在循环依赖关系。即使有办法让编译器消化这些代码,你的设计也至少值得怀疑。@Johanneschaub litb Nikos Athanasiou说得对!VS是对的。有趣的是,Clang也犯了这个错误,但幸运的是,它有一个解决问题的方法。这有一个好办法。我在bugzilla上搜索了一个bug报告,但没有找到任何具体的东西。同时也提到了这个问题。看来,对于实现者来说,要做到这一点是相当困难的。请随意使用此处的任何信息来改进您的答案;)@答案是肯定的,所以之前一致的答案似乎已经改变了。看起来我们都从中学到了一些东西。@prestokeys我从一开始就有了这个答案(这就是为什么我最初的答案是“我必须不同意”);在其他答案被删除后,我不得不改变这一点。从投票结果来看,我认为没有多少人对此印象深刻,所以我不得不假设这对社区来说也不是什么新鲜事。@prestokeys多亏了Nikos,我当然从中学到了一些东西;)。然而,这种情况经常发生在这类问题上。毕竟,这是宗教和科学之间的主要优势(即,科学没有教条,你可以有争议地说我错了!没有很多后果)。