C++模板朋友奇怪的行为
我在下面的代码中看到一些我无法解释的东西。在 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
}
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'. 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.
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.
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
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在您的示例中,
foo2
中的参数S
的类型是C1
。T2
和T1
之间存在好友关系。尽管C1
派生自T1
,但它并没有成为T1
的所有友元的友元。在表达式
pT1->bar
中,bar
在C1
中找到,并且由于友谊没有传递给派生类,因此它是私人的。您的示例使用的是虚函数,因此可以通过显式引用 类的友元
bar
来解决此问题:访问检查现在成功。
'03 C++ 标准中对此的参考位于 11.4/10,其中简单地说:
感谢 Potatoswatter 的评论。通过使用
qualified-id
作为id-expession
,我们禁用虚拟调度 (5.2.2/1):我们可以添加一个非虚拟调度程序,或者我们可以首先将参数转换为基本类型,然后进行调用:
现在根据需要进行虚拟调度。
In your example, the type of the parameter
S
infoo2
isC1
. The friend relationship exists betweenT2<S>
andT1<S>
. AlthoughC1
derives fromT1<C1>
it does not become a friend of all the friends ofT1<C1>
.In the expression
pT1->bar
,bar
is found inC1
and, as the friendship is not passed down to the derived class, it is private.Your example is using virtual functions so this can be addressed by explicitly referring to the
bar
that is a friend of our class:The access check now succeeds.
The reference for this in the '03 C++ standard is in 11.4/10, where it simply says:
Thanks to Potatoswatter for his comment. By using the
qualified-id
for theid-expession
, we disable virtual dispatch (5.2.2/1):We can add a non-virtual dispatcher, or we can first convert the parameter to the base type and then make the call:
Virtual dispatch now takes place as required.