在本例中,类 Foo
和 Bar
由图书馆提供。我的类(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
没有重命名的东西?
最佳答案
名称查找和重载解析是不同的。名称必须首先在作用域中找到,即我们必须找到 X
使名称do_stuff
解析为 X::do_stuff
-- 独立于名称的使用 -- 然后重载决议在 X::do_stuff
的不同声明之间进行选择.
该过程不是识别所有此类情况A::do_stuff
, B::do_stuff
等可见的,然后在其 union 中执行重载决议。相反,必须为名称标识单个范围。
在这段代码中:
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
的两个函数中进行选择.顺便说一句,阴影是名称查找的另一个结果(本身不是规则)。名称查找选择内部范围,因此外部范围内的任何内容都不匹配。
当依赖于参数的查找在起作用时,会出现更复杂的因素。简而言之,对于带有类类型参数的函数调用,名称查找会进行多次——我的回答中描述的基本版本,然后再对每个参数的类型进行一次。然后找到的范围的并集进入重载集。但这不适用于您的示例,因为您的函数只有内置类型的参数。
关于c++ - 多重继承导致虚假的模棱两可的虚函数重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58698154/