我有这个代码(钻石问题):
#include <iostream>
using namespace std;
struct Top
{
void print() { cout << "Top::print()" << endl; }
};
struct Right : Top
{
void print() { cout << "Right::print()" << endl; }
};
struct Left : Top
{
void print() { cout << "Left::print()" << endl; }
};
struct Bottom: Right, Left{};
int main()
{
Bottom b;
b.Right::Top::print();
}
我想在print()
课程中致电Top
。
当我尝试编译它时,我在此行收到错误:'Top' is an ambiguous base of 'Bottom'
:b.Right::Top::print();
为什么它含糊不清?我明确指出我需要来自Top
的{{1}},而不是来自Right
。
我不想知道怎么做,是的,可以通过引用,虚拟继承等来完成。我只是想知道为什么Left
不明确。
答案 0 :(得分:15)
为什么它含糊不清?我明确指出我需要来自
Top
的{{1}},而不是来自Right
。
这是你的意图,但事实并非如此。 Left
显式指定要调用的成员函数,即Right::Top::print()
。但它没有指定我们在哪个&Top::print
子对象上调用该成员函数。您的代码在概念上等同于:
b
选择auto print = &Bottom::Right::Top::print; // ok
(b.*print)(); // error
的部分是明确的。这是从print
到b
的隐含转换模糊不清。您必须通过以下操作明确消除您进入的方向的歧义:
Top
答案 1 :(得分:4)
范围解析运算符是左关联的(尽管它不允许使用括号)。
因此,虽然您想在A::tell
内引用B
,但id-expression指的是tell
内的B::A
,它只是A
,其中很暧昧。
解决方法是首先投射到明确的基础B
,然后再投射到A
。
语言 - 律师业:
[basic.lookup.qual] / 1说,
在
::
范围解析运算符应用于表示其类,命名空间或 nested-name-specifier 的::
范围解析运算符之后,可以引用类或命名空间成员或枚举数的名称。枚举。
嵌套名称说明符的相关语法是,
嵌套名称说明符:
type-name
::
嵌套名称说明符 标识符
B::
因此,第一个嵌套名称说明符为A
,并在其中查找B::A
。然后A
是一个嵌套名称说明符,表示tell
,并在其中查找parser.add_argument('--ensure', nargs='*', default=None)
ENSURE = config.ensure is None
。
显然MSVC接受了这个例子。可能它有一个非标准的扩展,通过回溯这些说明符来解决模糊性。
答案 2 :(得分:-1)
实际上,正如我在Visual Studio 2019上尝试的那样,提供代码可以正常工作。 有两种解决钻石问题的方法: -使用范围解析运算符 -继承基类为虚拟
通过b.Right::Top::print()
调用打印功能应正确执行。但是,您的底层类仍引用了基类(顶层)的两个对象。
您可以在here
中找到其他详细信息