多重继承会导致虚假的歧义虚拟函数重载

在此示例中,类FooBar是从库中提供的。我的课程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吗?

weilili123 回答:多重继承会导致虚假的歧义虚拟函数重载

您可以这样做:

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

最近用wandbox gcc进行了测试,并且编译良好。我认为函数重载也是这种情况,一旦重载,就不能没有using使用基类实现。

实际上,这与虚函数无关。以下示例具有相同的错误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,因此可以查找基类。但是名称以两个不同的基础出现,因此名称查找无法识别作用域。我们从来没有达到过载解决方案。

另一个答案中建议的修复程序有效,因为它在do_stuff的范围内引入了名称Baz,并且还为该名称引入了2个重载。因此,名称查找确定do_stuff的意思是Baz::do_stuff,然后从称为Baz::do_stuff的两个函数中选择重载分辨率。


顺便说一句, shadowing 是名称查找的另一个结果(本身不是规则)。名称查找将选择内部作用域,因此外部作用域中的所有内容都不匹配。

在进行与参数有关的查找时,会出现进一步的复杂因素。简而言之,对于具有类类型参数的函数调用,要多次进行名称查找-我的答案中所述的基本版本,然后针对每个参数的类型再次进行名称查找。然后,找到的范围的并集进入重载集合。但这不适用于您的示例,因为您的函数仅具有内置类型的参数。

本文链接:https://www.f2er.com/3164945.html

大家都在问