多重继承导致伪模糊虚函数重载

Multiple inheritence leads to spurious ambiguous virtual function overload

在此示例中,classes FooBar 由图书馆提供。我的 class Baz 继承自两者。

struct Foo
{
    void do_stuff (int, int);
};

struct Bar
{
    virtual void do_stuff (float) = 0;
};

struct Baz : public Foo, public Bar
{
    void func ()
    {
        do_stuff (1.1f); // ERROR HERE
    }
};

struct BazImpl : public Baz
{
    void do_stuff (float) override {};
};

int main ()
{
    BazImpl () .func ();
}

我收到编译错误 reference to ‘do_stuff’ is ambiguous,这对我来说似乎是虚假的,因为这两个函数签名完全不同。如果 do_stuff 是非虚拟的,我可以调用 Bar::do_stuff 来消除歧义,但这样做会破坏多态性并导致链接器错误。

我可以 func 在不重命名的情况下调用虚拟 do_stuff 吗?

你可以这样做:

struct Baz : public Foo, public Bar
{
    using Bar::do_stuff;
    using Foo::do_stuff;
    //...
}

使用最新的 wandbox gcc 进行测试,编译正常。我认为这与函数重载的情况相同,一旦你重载了一个,你就不能使用没有 using.

的基础 class 实现

其实这和虚函数无关。下面的例子同样报错GCC 9.2.0 error: reference to 'do_stuff' is ambiguous:

struct Foo
{
    void do_stuff (int, int){}
};

struct Bar
{
    void do_stuff (float) {}
};

struct Baz : public Foo, public Bar
{
    void func ()
    {
        do_stuff (1.1f); // ERROR HERE
    }
};

可能相关question

名称查找和重载解析不同。必须首先在作用域中找到该名称,即我们必须找到一个 X 以便将名称 do_stuff 解析为 X::do_stuff -- 与名称的用法无关 -- 然后重载决策在 X::do_stuff.

的不同声明之间进行选择

该过程不是识别所有可见的情况 A::do_stuffB::do_stuff 等,然后在其并集之间执行重载决议。相反,必须为名称标识单个范围。

在此代码中:

struct Baz : public Foo, public Bar
{
    void func ()
    {
        do_stuff (1.1f); // ERROR HERE
    }
};

Baz 不包含名称 do_stuff,因此可以查找基础 classes。但是名称出现在两个不同的基础上,因此名称查找无法识别范围。我们永远无法解决重载问题。

另一个答案中建议的修复是有效的,因为它将名称 do_stuff 引入了 Baz 的范围,并且还为该名称引入了 2 个重载。因此名称查找确定 do_stuff 表示 Baz::do_stuff,然后重载解析从称为 Baz::do_stuff.

的两个函数中进行选择

顺便说一句,shadowing 是名称查找的另一个结果(本身不是规则)。名称查找选择内部范围,因此外部范围内的任何内容都不匹配。

参数相关查找 正在运行时,会出现一个更复杂的因素。简而言之,对于带有 class 类型参数的函数调用,会多次执行名称查找——我的回答中描述的基本版本,然后针对每个参数的类型再次进行名称查找。然后找到的作用域的并集进入重载集。但这不适用于您的示例,因为您的函数只有内置类型的参数。