[英]Multiple inheritence leads to spurious ambiguous virtual function overload
In this example, classes Foo
and Bar
are provided from a library.在此示例中,类
Foo
和Bar
是从库中提供的。 My class Baz
inherits from both.我的 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 ();
}
I get the compilation error reference to 'do_stuff' is ambiguous
which seems spurious to me since the two function signatures are entirely different.我得到
reference to 'do_stuff' is ambiguous
,这对我来说似乎是虚假的,因为两个 function 签名完全不同。 If do_stuff
was non-virtual I could call Bar::do_stuff
to disambiguate it, but to do so breaks polymorphism and causes a linker error.如果
do_stuff
是非虚拟的,我可以调用Bar::do_stuff
来消除歧义,但这样做会破坏多态性并导致 linker 错误。
Can I make func
call the virtual do_stuff
without renaming things?我可以在不重命名的情况下让
func
调用虚拟do_stuff
吗?
You can do this:你可以这样做:
struct Baz : public Foo, public Bar
{
using Bar::do_stuff;
using Foo::do_stuff;
//...
}
Tested with wandbox gcc latest and it compiles fine.用最新的wandbox gcc 测试,编译良好。 I think it's the same case with function overloads, once you overload one you can't use base class implementations without
using
.我认为 function 重载的情况相同,一旦重载一个,你就不能使用基本 class 实现而不
using
.
In fact this has nothing to do with virtual functions.实际上这与虚函数无关。 The following example has the same error
GCC 9.2.0 error: reference to 'do_stuff' is ambiguous
:以下示例具有相同的错误
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
}
};
Name lookup and overload resolution are different.名称查找和重载解析是不同的。 The name must be found in a scope first, ie we must find an
X
so that the name do_stuff
is resolved to X::do_stuff
-- independently of the usage of the name -- and then overload resolution selects between the different declarations of X::do_stuff
.该名称必须首先在 scope 中找到,即我们必须找到一个
X
以便将名称do_stuff
解析为X::do_stuff
与名称的使用无关——然后重载解析在X::do_stuff
的不同声明之间进行选择X::do_stuff
。
The process is NOT to identify all such cases A::do_stuff
, B::do_stuff
, etc. that are visible, and then perform overload resolution amongst the union of that.该过程不是识别所有可见
A::do_stuff
、 B::do_stuff
等情况,然后在它们的联合中执行重载解决方案。 Instead, a single scope must be identified for the name.相反,必须为名称标识单个 scope。
In this code:在这段代码中:
struct Baz : public Foo, public Bar
{
void func ()
{
do_stuff (1.1f); // ERROR HERE
}
};
Baz
does not contain the name do_stuff
, so base classes can be looked up. Baz
不包含名称do_stuff
,因此可以查找基类。 But the name occurs in two different bases, so name lookup fails to identify a scope.但名称出现在两个不同的基数中,因此名称查找无法识别 scope。 We never get so far as overload resolution.
我们从来没有达到过重载决议。
The suggested fix in the other answer works because it introduces the name do_stuff
to the scope of Baz
, and also introduces 2 overloads for the name.另一个答案中的建议修复有效,因为它将名称
do_stuff
引入了Baz
的 scope ,并且还为该名称引入了 2 个重载。 So name lookup determines that do_stuff
means Baz::do_stuff
and then overload resolution selects from the two functions that are known as Baz::do_stuff
.因此,名称查找确定
do_stuff
表示Baz::do_stuff
,然后重载决议从称为Baz::do_stuff
的两个函数中进行选择。
As an aside, shadowing is another consequence of name lookup (not a rule in itself).顺便说一句,阴影是名称查找的另一个结果(本身不是规则)。 Name lookup selects the inner scope, and so anything in the outer scope is not a match.
名称查找选择内部 scope,因此外部 scope 中的任何内容都不匹配。
A further complicating factor occurs when argument-dependent lookup is in play.当依赖于参数的查找在起作用时,会出现更复杂的因素。 To summarize very briefly, name lookup is done multiple times for a function call with arguments of class type -- the basic version as described in my answer, and then again for each argument's type.
简而言之,对于使用 class 类型的 arguments 的 function 调用(我的回答中描述的基本版本),名称查找会进行多次,然后再针对每个参数类型。 Then the union of the scopes found goes into the overload set.
然后找到的范围的联合进入重载集。 But that does not apply to your example since your function only has parameters of built-in type.
但这不适用于您的示例,因为您的 function 只有内置类型的参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.