请考虑以下代码:
struct A
{
void f()
{
}
};
struct B1 : A
{
};
struct B2 : A
{
};
struct C : B1, B2
{
void f() // works
{
B1::f();
}
//using B1::f; // does not work
//using B1::A::f; // does not work as well
};
int main()
{
C c;
c.f();
return 0;
}
我恳请你不要复制粘贴标准答案如何解决钻石问题(“使用虚拟继承”)。我在这里问的是为什么在这种情况下使用声明不起作用。确切的编译错误是:
In function 'int main()':
prog.cpp:31:6: error: 'A' is an ambiguous base of 'C'
c.f();
我得到的印象是,使用声明应该可以从这个例子开始:
struct A
{
void f()
{
}
};
struct B
{
void f()
{
}
};
struct C : A, B
{
using A::f;
};
int main()
{
C c;
c.f(); // will call A::f
return 0;
}
答案 0 :(得分:56)
其他人可以找到标准报价但我会在概念上解释。
它不起作用,因为 using-declaration 仅影响名称查找。
using-declaration 会导致名称查找成功,否则会失败,也就是说,它会告诉编译器在哪里找到函数f
。但它并没有告诉它 A
子对象f
作用于,也就是说,当this
时,哪一个将作为隐式f
参数传递被称为。
即使A::f
有两个A
子对象,也只有一个函数C
,它采用类型为this
的隐式A*
参数。要在C
对象上调用它,C*
必须隐式转换为A*
。这总是不明确的,不受任何 using-declarations 的影响。
(如果您将数据成员放在A
中,这会更有意义。然后C
会有两个这样的数据成员。当f
被调用时,如果它访问数据成员,它是否访问从A
继承的B1
子对象或从A
继承的B2
子对象中的对象?)
答案 1 :(得分:28)
[namespace.udecl] / p17中的注释直接解决了这种情况:
[注意:因为 using-declaration 指定了基类成员 (而不是成员子对象或基类的成员函数 子对象), using-declaration 不能用于解析继承 成员含糊不清。例如,
struct A { int x(); }; struct B : A { }; struct C : A { using A::x; int x(int); }; struct D : B, C { using C::x; int x(double); }; int f(D* d) { return d->x(); // ambiguous: B::x or C::x }
- 结束记录]
答案 2 :(得分:5)
除了T.C.的回答之外,我想补充一点,派生类中的名称查找在10.2节中详细解释了标准。
这里有关于使用声明处理的内容:
10.2 / 3:查找集(...)由两个组件集组成:声明集,一组名为f的成员;和子对象集,一组子对象,其中声明这些成员(可能包括 找到了使用声明。在声明集中, using-declarations由他们指定的成员替换,并且类型声明(包括 注入类名称由他们指定的类型替换。
因此,当您尝试在tv.setMaxWidth(((LinearLayout)tv.getParent()).getWidth()/3);
struct C
根据查找规则,您的编译器仍会找到可能的候选者:using B1::f; // you hope to make clear that B1::f is to be used
和B1::f
,因此它仍然不明确。