This question already has answers here:
Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?

(3个答案)


7年前关闭。




考虑以下类别:
class Foo
{
    public:

    void operator [] (const std::string& s) { }

    void operator [] (std::size_t idx) { }
};

在此,给定Foo f的实例,表达式f[0]并不模棱两可,因为编译器选择了第二个重载。同样,表达式f["abc"]也不是模棱两可的,因为编译器会选择第一个重载(因为const char*可转换为std::string)。

那么,为什么要这样呢?如果我们有两个基类,每个基类都有不同的重载,突然之间就会有歧义?

假设我们有:
class Base1
{
    public:

    void operator [] (const std::string& s) { }
};

class Base2
{
    public:

    void operator [] (std::size_t idx) { }
};

class Derived : public Base1, public Base2
{ };

现在,如果我们说:
Derived d;
d[0];

编译器提示:
    error: request for member ‘operator[]’ is ambiguous
      d[0];
         ^
   note: candidates are: void Base2::operator[](std::size_t)
      void operator [] (std::size_t idx) { }
           ^
   note:                 void Base1::operator[](const string&)
      void operator [] (const std::string& s) { }

为什么两个运算符重载现在都在Base类中的事实会引起歧义?有解决此问题的方法吗?

编辑:这可能是编译器错误(我正在使用GCC 4.8.1)

最佳答案

这不是过载解析的问题,而是成员名称查找(在10.2中定义)的问题。考虑一下(因为我宁愿不要到处都写operator[]):

struct base1 { void f(int); };
struct base2 { void f(double); };
struct derived : base1, base2 {};
int main() {
   derived d; d.f(0);
}
当在后缀表达式f中开始查找d.f(0)时,它将首先调查derived并发现f根本无法解析任何内容。然后,10.2/5要求并行进行所有基类的查找,并构造单独的查找集。在这种情况下,S(f,base1)= {base1::f}和S(f,base2)= {base2::f}。然后按照10.2/6中的规则合并这些集合。第一个项目符号是当集合中的一个为空时,或者如果对不同集合的查找以相同成员结尾(考虑到它具有共同的基础)时,则进行合并。第二个项目符号很有趣,因为它适用于此处

也就是说,S(f,base1)与S(f,base2)不同,因此S(f,derived)成为无效的声明集。并且查找失败。

关于c++ - []运算符和多重继承的歧义,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19276238/

10-09 21:03