简体   繁体   English

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

[英]Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?

The following snippet produces an "ambigious call to foo" error during compilation, and I'd like to know if there is any way around this problem without fully qualifying the call to 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;
}

So, question is as the title says.所以,问题正如标题所说。 Ideas?想法? I mean, the following works flawlessly:我的意思是,以下工作完美无缺:

#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;
}

Member lookup rules are defined in Section 10.2/2成员查找规则在第 10.2/2 节中定义

The following steps define the result of name lookup in a class scope, C .以下步骤定义类范围C中名称查找的结果。 First, every declaration for the name in the class and in each of its base class sub-objects is considered.首先,考虑类及其每个基类子对象中名称的每个声明。 A member name f in one sub-object B hides a member name f in a sub-object A if A is a base class sub-object of B .成员名称f在一个子对象B兽皮的成员名f在一个子对象A如果A是一个基类的子对象B Any declarations that are so hidden are eliminated from consideration .任何如此隐藏的声明都将不予考虑 Each of these declarations that was introduced by a using-declaration is considered to be from each sub-object of C that is of the type containing the declara-tion designated by the using-declaration.通过 using 声明引入的这些声明中的每一个都被认为来自C每个子对象,这些子对象属于包含 using 声明指定的声明的类型。 If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed .如果生成的声明集并非全部来自相同类型的子对象,或者该集合具有非静态成员并包含来自不同子对象的成员,则存在歧义且程序格式错误 Otherwise that set is the result of the lookup.否则,该集合是查找的结果。

class A {
public:
  int f(int);

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

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

So you can use the using declarations A::f and B::f to resolve that ambiguity所以你可以使用using声明A::fB::f来解决这种歧义

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

};

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

The second code works flawlessly because void foo(float) is inside C's scope.第二个代码完美无缺,因为void foo(float)在 C 的范围内。 Actually d.foo(5);实际上d.foo(5); calls void foo(float) and not the int version.调用void foo(float)而不是int版本。

Name lookup is a separate phase to overload resolution .名称查找重载解析的一个单独阶段。

Name lookup occurs first.首先进行名称查找。 That is the process of deciding which scope the name applies to.这是决定名称适用于哪个范围的过程。 In this case we must decide whether d.foo means dD::foo , or d.B1::foo , or d.B2::foo .在这种情况下,我们必须决定d.foo是指dD::foo ,还是d.B1::foo ,还是d.B2::foo The name lookup rules do not take into account function parameters or anything;名称查找规则不考虑函数参数或任何东西; it is purely about names and scopes.它纯粹是关于名称和范围的。

Only once that decision has been made, do we then perform overload resolution on the different overloads of the function in the scope where the name was found.只有在做出该决定后,我们才能在找到名称的范围内对函数的不同重载执行重载解析。

In your example, calling d.foo() would find D::foo() if there were such a function.在您的示例中,如果有这样的函数,调用d.foo()会找到D::foo() But there is none.但没有。 So, working backwards up the scopes, it tries the base classes.因此,向后工作范围,它尝试基类。 Now foo could equally look up to B1::foo or B2::foo so it is ambiguous.现在foo可以同样查找B1::fooB2::foo所以它是模棱两可的。

For the same reason, you would get ambiguity calling unqualified foo(5);出于同样的原因,调用不合格的foo(5);会产生歧义foo(5); inside a D member function.D成员函数中。


The effect of the recommended solution:推荐方案的效果:

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

is that this creates the name D::foo , and makes it identify two functions.是因为这会创建名称D::foo ,并使其标识两个函数。 The result is that d.foo resolves to dD::foo , and then overload resolution can happen on these two functions that are identified by D::foo .结果是d.foo解析为dD::foo ,然后重载解析可以发生在这两个由D::foo标识的函数上。

Note: In this example D::foo(int) and Base1::foo(int) are two identifiers for the one function;注意:在这个例子中, D::foo(int)Base1::foo(int)是一个函数的两个标识符; but in general, for the name lookup and overload resolution process, it doesn't make a difference whether they are two separate functions or not.但总的来说,对于名称查找和重载解析过程,它们是否是两个单独的函数并没有区别。

Will it work for you?它对你有用吗?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将具有相同名称的继承函数视为重载函数? - How can inherited functions with the same name get treated as overloaded functions? 多态性和具有不同签名的重载函数 - Polymorphism and overloaded functions with different signatures 为什么歧义只适用于重载运算符而不适用于具有“相同”名称但不同 scope 的函数? - Why ambiguity only for overloaded operators and not for functions with "same" name but different scope? 多继承派生类:如何重用派生函数而不重复调用基类 - Multiple-inherited derived class: How to reuse derived functions without repeating calls to base 为什么重载的继承静态函数不明确? - Why are overloaded inherited static functions ambiguous? 确定重载成员函数的签名 - Determine signatures of overloaded member functions 如何为具有不同签名的功能分配相同的签名? - How to assign same signature to functions with different signatures? 具有相同名称的抽象和已定义继承函数的多重继承 - Multiple Inheritance with abstract and defined inherited functions of the same name 具有不同签名的绑定功能 - Binding functions with different signatures 具有不同签名的函数数组 - Array of functions with different signatures
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM