为什么具有相同名称但签名不同的多重继承函数不会被视为重载函数?

时间:2011-03-20 13:46:52

标签: c++ scope overloading multiple-inheritance

下面的代码片段在编译过程中产生了一个“foo调用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;
}

3 个答案:

答案 0 :(得分:45)

成员查找规则在第10.2 / 2节中定义

  

以下步骤定义类范围C中的名称查找结果。首先,考虑类中及其每个基类子对象中的名称的每个声明。如果f是基类子对象,则一个子对象B中的成员名称f会在子对象A中隐藏成员名称A B任何隐藏的声明都会被排除在考虑之外。由using声明引入的每个声明都被认为是来自C的每个子对象,它们是包含using声明指定的声明的类型。 如果生成的声明集不是全部来自相同类型的子对象,或者该集合具有非静态成员并且包含来自不同子对象的成员,则存在歧义并且程序格式错误。否则该集合是查找的结果。

class A {
public:
  int f(int);

};
class B {
public:
   int f();

};
class C : public A, public B {};
int main()
{
     C c;
     c.f(); // ambiguous
}

因此,您可以使用using声明A::fB::f来解决这种歧义

class C : public A, public B {
     using A::f;
     using B::f;

};

int main()
{
     C c;
     c.f(); // fine
}

第二个代码完美无缺,因为void foo(float)在C的范围内。实际上d.foo(5);会调用void foo(float)而不是int版本。

答案 1 :(得分:4)

名称查找重载决策的单独阶段。

首先进行名称查找。这是决定名称适用范围的过程。在这种情况下,我们必须确定d.food.D::foo,还是d.B1::foo还是d.B2::foo。名称查找规则不考虑函数参数或任何东西;它纯粹是关于名称和范围。

只有做出决定后,我们才会对找到名称的范围内的函数的不同重载执行重载解析。

在您的示例中,如果有这样的功能,调用d.foo()会找到D::foo()。但没有。因此,向后工作范围,它会尝试基类。现在foo同样可以查看B1::fooB2::foo,因此它不明确。

出于同样的原因,你会在foo(5);成员函数中调用不合格D的歧义。

推荐解决方案的效果:

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

这将创建名称D::foo,并使其识别两个函数。结果是d.foo解析为d.D::foo,然后在D::foo标识的这两个函数上发生重载解析。

注意:在此示例中,D::foo(int)Base1::foo(int)是一个函数的两个标识符;但一般来说,对于名称查找和重载解析过程,它们是否是两个独立的函数并没有区别。

答案 2 :(得分:2)

它会对你有用吗?

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