为什么具有相同名称但签名不同的多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中名称查找的结果。 首先,考虑每个类中的名称和每个基类子对象的声明。 如果AB的基类子对象,则在一个子对象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::fB::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::food.B2::foo 。 名称查找规则不考虑函数参数或任何东西; 它纯粹是关于名称和范围。

只有做出了这个决定,我们才能对名称范围内的函数的不同重载执行重载parsing。

在你的例子中,如果有这样一个函数,调用d.foo()会findD::foo() 。 但是没有。 所以,向后向上的范围,它会尝试基类。 现在foo可以同样查找B1::fooB2::foo所以它是不明确的。

出于同样的原因,你会得到含糊不清的foo(5); 里面有一个D成员函数。


推荐解决scheme的效果:

 struct Derived : public Base1, public Base2{ using Base1::foo; using Base2::foo; 

这是创build名称D::foo ,并使其识别两个函数。 其结果是d.fooparsing为dD::foo ,然后重载parsing可能发生在由D::foo标识的这两个函数上。

注意:在这个例子中, D::foo(int)Base1::foo(int)是一个函数的两个标识符; 但一般而言,对于名称查找和重载parsing过程,它们是否是两个单独的函数并没有什么不同。