繁体   English   中英

死亡钻石和范围解析运算符(C ++)

[英]Diamond of death and Scope resolution operator (c++)

我有此代码(钻石问题):

#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();
}

我想在Top类中调用print()

当我尝试对其进行编译时,出现错误: 'Top' is an ambiguous base of 'Bottom'此行上'Top' is an ambiguous base of 'Bottom'b.Right::Top::print(); 为什么模棱两可? 我明确指定要从Right Top Right而不是“ Top Left

我不想知道如何去做,是的,它可以通过引用,虚拟继承等来完成。我只是想知道为什么b.Right::Top::print(); 暧昧。

为什么模棱两可? 我明确指定要从Right Top Right而不是“ Top Left

那是您的意图,但实际上并非如此。 Right::Top::print()明确命名您要调用的成员函数,即&Top::print 但是它没有指定我们在b哪个子对象上调用该成员函数。 您的代码在概念上等效于:

auto print = &Bottom::Right::Top::print;  // ok
(b.*print)();                             // error

选择print的部分是明确的。 bTop的隐式转换是模棱两可的。 您必须通过执行以下操作来明确消除前进的方向:

static_cast<Right&>(b).Top::print();

范围解析运算符是左关联的(尽管它不允许使用括号)。

因此,虽然您想在B内部引用A::tell ,但id-expression却在B::A内部tell ,这就是A ,这是模棱两可的。

解决方法是先强制转换为明确的基B ,然后再次强制转换为A

语言咨询:

[basic.lookup.qual] / 1说,

在将::作用域解析运算符应用于表示其类,名称空间或枚举的嵌套名称说明符之后, ::类或名称空间成员或枚举器的名称

嵌套名称说明符的相关语法为:

嵌套名称说明符:

类型名称 ::

嵌套名称说明 标识符 ::

因此,第一个嵌套名称说明符B::并且在其中查找A 然后B::A是表示A的嵌套名称说明符,并在其中查找tell

显然,MSVC接受该示例。 它可能具有非标准扩展,可以通过在此类说明符中回溯来解决歧义。

实际上,正如我在Visual Studio 2019上尝试过的那样,提供代码可以正常工作。有两种解决钻石问题的方法; -使用范围解析运算符-将基类继承为虚拟

通过b.Right::Top::print()调用print函数应正确执行。 但是,您的底层类仍引用了基类(顶层)的两个对象。

您可以在这里找到更多详细信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM