为什么具有相同名称但签名不同的多inheritance函数不被视为重载函数?
下面的代码片段在编译过程中会产生一个“非法调用foo”的错误,我想知道是否有任何方法解决这个问题,而没有完全限定对foo的调用:
#include <iostream> struct Base1{ void foo(int){ } }; struct Base2{ void foo(float){ } }; struct Derived : public Base1, public Base2{ }; int main(){ Derived d; d.foo(5); std::cin.get(); return 0; }
所以问题就像标题所说的那样。 想法? 我的意思是,以下作品完美无瑕:
#include <iostream> struct Base{ void foo(int){ } }; struct Derived : public Base{ void foo(float){ } }; int main(){ Derived d; d.foo(5); std::cin.get(); return 0; }
成员查找规则在10.2.2节中定义
以下步骤定义了类范围
C
中名称查找的结果。 首先,考虑每个类中的名称和每个基类子对象的声明。 如果A
是B
的基类子对象,则在一个子对象B
的成员名称f
隐藏子对象B
的成员名称f
。 任何隐藏的声明都会被忽略 。 使用声明引入的每个声明都被认为是来自C
每个子对象,这些子对象是包含由using声明指定的声明的types。 如果所得到的一组声明不是全部来自同一types的子对象,或者该组具有非静态成员并且包含来自不同子对象的成员,则存在不明确性,并且该程序是不合格的 。 否则,该设置是查找的结果。
class A { public: int f(int); }; class B { public: int f(); }; class C : public A, public B {}; int main() { C c; cf(); // ambiguous }
所以你可以使用using
声明A::f
和B::f
来解决这个歧义
class C : public A, public B { using A::f; using B::f; }; int main() { C c; cf(); // fine }
第二个代码完美地工作,因为void foo(float)
在C的范围内。 其实d.foo(5);
调用void foo(float)
而不是int
版本。
它会为你工作吗?
struct Derived : public Base1, public Base2{ using Base2::foo;}
名称查找是重载parsing的单独阶段。
名称查找首先发生。 这是决定名称适用于哪个范围的过程。 在这种情况下,我们必须决定d.foo
是指dD::foo
,还是d.B1::foo
或d.B2::foo
。 名称查找规则不考虑函数参数或任何东西; 它纯粹是关于名称和范围。
只有做出了这个决定,我们才能对名称范围内的函数的不同重载执行重载parsing。
在你的例子中,如果有这样一个函数,调用d.foo()
会findD::foo()
。 但是没有。 所以,向后向上的范围,它会尝试基类。 现在foo
可以同样查找B1::foo
或B2::foo
所以它是不明确的。
出于同样的原因,你会得到含糊不清的foo(5);
里面有一个D
成员函数。
推荐解决scheme的效果:
struct Derived : public Base1, public Base2{ using Base1::foo; using Base2::foo;
这是创build名称D::foo
,并使其识别两个函数。 其结果是d.foo
parsing为dD::foo
,然后重载parsing可能发生在由D::foo
标识的这两个函数上。
注意:在这个例子中, D::foo(int)
和Base1::foo(int)
是一个函数的两个标识符; 但一般而言,对于名称查找和重载parsing过程,它们是否是两个单独的函数并没有什么不同。