多重继承导致虚假的模糊虚拟函数过载

Multiple inheritence leads to spurious ambiguous virtual function overload

本文关键字:虚拟 函数 模糊 多重继承      更新时间:2023-10-16

在本例中,类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而不重命名东西吗?

您可以这样做:

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

可能的相关问题

名称查找和重载解析不同。必须首先在作用域中找到名称,即我们必须找到一个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的两个函数中进行选择。


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

参数相关查找正在进行时,会出现更复杂的因素。简单地说,对于具有类类型参数的函数调用(如我的回答中所述的基本版本(,会多次进行名称查找,然后对每个参数的类型再次进行名称查找。然后,找到的作用域的并集进入重载集。但这并不适用于您的示例,因为您的函数只有内置类型的参数。