C++ 模板 friend 奇怪的行为

标签 c++ templates friend

我在下面的代码中看到一些我无法解释的东西。在 VS6、VS9 和 GCC T2::foo2() 下给出错误:“bar”:无法访问类“C1”中声明的 protected 成员。但是,如果您删除 C1::bar(),它会正确编译和运行,即使 T2 仍在访问 protected C1B:bar(),您会认为这会是同样的问题。

请注意,在 T2::foo2() 中,您可以将 'pT1' 转换为 'T1*',一切都很好,但这仍然不能解释为什么允许 C1B::bar(),但 C1: :bar() 不是。

template<class S> class T2;

template<class T> class T1
{
    //template<class T> friend class T2;  --> this doesn't compile under VS6
    friend class T2<T>;

    protected:
        virtual void bar() { printf("T1\n"); }
};

template<class S> class T2
{
    public:
        void foo1(T1<S> *pT1) { pT1->bar(); }  // --> ok, makes sense, this works either way
        void foo2(S *pT1) { pT1->bar(); }  // --> this fails to compile if C1::bar() is defined, but works for C1B::foo() ???
};

class C1 : public T1<C1>
{
    protected:
        virtual void bar() { printf("C1\n"); }  // --> comment this out and foo2 will compile
};

class C1B : public  C1
{
    protected:
        virtual void bar() { printf("C1B\n"); }
};

class C2 : public  T2<C1>
{
};

void test(void)
{
    C1B c1b;
    C2 c2;
    c2.foo1(&c1b);
    c2.foo2(&c1b);  // --> fails to compile if C1::bar() exists
}

最佳答案

在您的示例中,参数的类型 Sfoo2C1 . T2<S>之间存在好友关系和 T1<S> .虽然C1源自 T1<C1>它不会成为所有 friend 的 friend T1<C1> .

在表达式 pT1->bar 中, barC1 中找到而且,由于友元不会传递给派生类,因此它是私有(private)的。

您的示例使用虚函数,因此可以通过显式引用 bar 来解决这个问题那我们类的一个 friend :

void foo2(S *pT1) { pT1->template T1<S>::bar(); }

现在访问检查成功。

'03 C++ 标准中对此的引用是在 11.4/10 中,它只是说:

Friendship is neither inherited nor transitive.

感谢 Potatoswatter 的评论。通过使用 qualified-id对于 id-expession ,我们禁用虚拟调度(5.2.2/1):

If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called.

我们可以添加一个非虚拟调度器,或者我们可以先将参数转换为基本类型,然后再进行调用:

 void foo2(S *pT1) { static_cast< T1<S>* > (pT1)->bar(); }

现在可以根据需要进行虚拟调度。

关于C++ 模板 friend 奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5968273/

相关文章:

c++ - 为什么这个友元函数不能访问私有(private)变量?

c++ - 无法使用regex c++ 11 std在Windows中运行使用minGW编译的程序

c++ - 有没有办法压缩 vector (C++)?

email - Grails邮件插件:查看的绝对路径

c++ - 友元函数是否违反封装?

ios ShareKit 2.0 从 facebook 获取用户好友列表的方法?

c++ - 链接器错误 : DLL and inheritance

c++ - Python 的 "in"运算符的 C++ 等价物是什么?

c++ - < : cannot begin a template argument list

c++ - 使用参数包作为模板类的类型名