考虑这个小例子:
#include <iostream>
struct A
{
void foo()
{
std::cout << "A::foo" << std::endl;
}
};
struct B
{
void foo()
{
std::cout << "B::foo" << std::endl;
}
};
struct C:private A
{
using A::foo;
};
struct D:private B, public C
{
};
int main()
{
D myD;
myD.foo();
return 0;
}
使用g ++ 4.8.1编译此示例时,我收到以下错误:
prog.cpp: In function ‘int main()’:
prog.cpp:32:9: error: request for member ‘foo’ is ambiguous
myD.foo();
^
prog.cpp:5:10: note: candidates are: void A::foo()
void foo()
^
prog.cpp:5:10: note: void A::foo()
prog.cpp:13:10: note: void B::foo()
void foo()
我原本以为D :: foo()的查找会忽略B :: foo(),因为B是D私下继承而D中没有using
声明。会想到唯一可见的foo()将是A :: foo()。
但显然我认为错了,我误解了using
声明的一个方面。
任何人都可以解释:
为什么B :: foo()在这里可见
如何让编译器只看到A :: foo()而不改变A,B或C的公共接口?
答案 0 :(得分:6)
1)在名称查找过程中,辅助功能被忽略:如果该成员是公共的,私有的还是受保护的,则无关紧要:所有这些都被同等考虑,这就是为什么{ {1}}和A::foo
在B::foo
内不明确。
C ++标准第3.4节[basic.lookup]:
访问规则(第11条)仅在名称查找和功能重载解析(如果适用)成功后才被视为
2)只需将其纳入D
:
D
答案 1 :(得分:4)
为什么
B::foo()
在这里可见
访问限制不会影响名称查找期间名称的可见性;只有在查找找到明确的匹配后才会检查它们。
如何让编译器只看到A :: foo()而不改变A,B或C的公共接口?
将using C::foo;
添加到D
。这隐藏了基类中同名的任何声明,因此D
中只能看到那个重载。
或者,限定函数调用:myD.C::foo()
答案 2 :(得分:0)
我不确定为什么会发生冲突。值得庆幸的是,它很容易解决:
struct D:private B, public C
{
using C::foo;
};