[英]C++ Template friend odd behavior
I'm seeing something I can't explain in the following code. 我在下面的代码中看到了一些我无法解释的内容。 Under VS6, VS9, and GCC T2::foo2() gives the error: 'bar' : cannot access protected member declared in class 'C1'. 在VS6,VS9和GCC T2 :: foo2()下给出错误:'bar':无法访问在类'C1'中声明的受保护成员。 But if you remove C1::bar(), it compiles and runs correctly, even though T2 is still accessing the protected C1B:bar(), which you would think would be the same problem. 但是如果你删除C1 :: bar(),它会编译并正确运行,即使T2仍在访问受保护的C1B:bar(),你会认为这是同样的问题。
Note, that in T2::foo2() you could cast 'pT1' to be a 'T1*' and everything is fine, but that still does not explain why C1B::bar() is allowed, but C1::bar() is not. 注意,在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
}
In your example, the type of the parameter S
in foo2
is C1
. 在您的示例中, foo2
参数S
的类型为C1
。 The friend relationship exists between T2<S>
and T1<S>
. T2<S>
和T1<S>
之间存在朋友关系。 Although C1
derives from T1<C1>
it does not become a friend of all the friends of T1<C1>
. 虽然C1
来自T1<C1>
但它不会成为所有T1<C1>
的朋友的朋友。
In the expression pT1->bar
, bar
is found in C1
and, as the friendship is not passed down to the derived class, it is private. 在表达式pT1->bar
, bar
在C1
找到,并且由于友谊不会传递给派生类,因此它是私有的。
Your example is using virtual functions so this can be addressed by explicitly referring to the bar
that is a friend of our class: 您的例子是使用虚拟功能,因此这可以通过明确提到要解决bar
是我们班的一个朋友:
void foo2(S *pT1) { pT1->template T1<S>::bar(); }
The access check now succeeds. 访问检查现在成功。
The reference for this in the '03 C++ standard is in 11.4/10, where it simply says: '03 C ++标准中的参考文献是11.4 / 10,它只是说:
Friendship is neither inherited nor transitive. 友谊既不是遗传也不是传递。
Thanks to Potatoswatter for his comment. 感谢Potatoswatter的评论。 By using the qualified-id
for the id-expession
, we disable virtual dispatch (5.2.2/1): 通过使用id-expession
的qualified-id
,我们禁用虚拟调度(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. 如果所选函数是非虚拟的,或者类成员访问表达式中的id-expression是quali-ed-id,则调用该函数。
We can add a non-virtual dispatcher, or we can first convert the parameter to the base type and then make the call: 我们可以添加一个非虚拟调度程序,或者我们可以先将参数转换为基类型然后进行调用:
void foo2(S *pT1) { static_cast< T1<S>* > (pT1)->bar(); }
Virtual dispatch now takes place as required. 现在可以根据需要进行虚拟调度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.