Gre*_*reg 6 c++ templates friend
我在下面的代码中看到了一些我无法解释的内容.在VS6,VS9和GCC T2 :: foo2()下给出错误:'bar':无法访问在类'C1'中声明的受保护成员.但是如果你删除C1 :: bar(),它会编译并正确运行,即使T2仍在访问受保护的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
}
Run Code Online (Sandbox Code Playgroud)
在您的例子中,参数的类型S中foo2是C1.朋友关系存在于T2<S>和之间T1<S>.虽然C1源于T1<C1>它并没有成为所有朋友的朋友T1<C1>.
在表达式中pT1->bar,bar找到C1并且,因为友谊没有传递给派生类,所以它是私有的.
您的例子是使用虚拟功能,因此这可以通过明确提到要解决bar这是我们班的一个朋友:
void foo2(S *pT1) { pT1->template T1<S>::bar(); }
Run Code Online (Sandbox Code Playgroud)
访问检查现在成功.
'03 C++标准中的参考文献是11.4/10,它只是说:
友谊既不是遗传也不是传递.
感谢Potatoswatter的评论.通过使用qualified-idfor id-expession,我们禁用虚拟调度(5.2.2/1):
如果所选函数是非虚拟的,或者类成员访问表达式中的id-expression是quali-ed-id,则调用该函数.
我们可以添加一个非虚拟调度程序,或者我们可以先将参数转换为基类型然后进行调用:
void foo2(S *pT1) { static_cast< T1<S>* > (pT1)->bar(); }
Run Code Online (Sandbox Code Playgroud)
现在可以根据需要进行虚拟调度.
| 归档时间: |
|
| 查看次数: |
205 次 |
| 最近记录: |