15

MSVC、Clang 和 GCC 对此代码存在分歧:

struct Base { int x; };
struct Der1 : public  Base {};
struct Der2 : public  Base {};

struct AllDer : public Der1, public Der2 {
    void foo() {
        Der1::Base::x = 5;
    }
};

神螺栓

海合会:

<source>: In member function 'void AllDer::foo()':    
<source>:10:21: error: 'Base' is an ambiguous base of 'AllDer'    
   10 |         Der1::Base::x = 5;    
      |                     ^    
Compiler returned: 1

Clang 给出了类似的错误,而 MSVC 没有给出错误。

谁在这里?

我想这在[class.member.lookup]中有所涉及,但我很难理解它试图告诉我这个案例的内容。请引用相关部分,并尽可能用简单的英语解释。

PS:受这个问题的启发,为什么对基类的引用与 :: -operator 槽派生类不明确?

PPS:实际上我的疑问是Der1::Base指的是类型,那将是Base(然后Der2::Base是完全相同的类型),或者是子对象。我确信它是第一个,但如果是后者,那么 MSVC 将是正确的。

4

2 回答 2

6

要回答标题中的问题,是的,Derived1::Base引用注入的类名称[class.pre] BaseDerived2::Base. 两者都指类::Base

现在,如果Base有一个静态成员x,那么查找Base::x将是明确的。只有一个。

这个例子中的问题是它x是一个非静态成员,并且AllDer两个这样的成员。x您可以通过指定只有一个成员的明确基类来消除此类访问的歧义。是一个明确的基类,并且它有一个成员,因此明确指定您的意思是两个成员中的哪一个。too 只有一个成员,但它不是. 的每个实例都有两个类型的子对象。因此在你的例子中是模棱两可的。由于只是 的另一个名称,因此这仍然是模棱两可的。AllDerxDerived1xDerived1::xxAllDerBasexAllDerAllDerBaseBase::xDerived1::BaseBase

[class.member.lookup] 指定x在嵌套名称说明符的上下文中查找,因此必须首先解决。我们确实在寻找Base::x,不是Derived1::x,因为我们从解决Derived1::Baseas开始Basex这部分成功了,[class.member.lookup]中的注释 12 中只有一个Base.明确告诉您,当有多个具有相同名称的子对象时,使用明确的名称查找可能仍然会失败。D::i在那个例子中基本上是你的Base::x.

于 2020-04-28T11:14:13.030 回答
2

之所以可以将类名引用为类的成员,是因为 cpp 为它取别名以便于使用,就像你using Base = ::Base;在 Base 中写的一样。
您面临的问题Der1::BaseBase.
因此,当您编写 时Der1::Base::x,它与Base::x.

于 2020-04-28T09:52:45.237 回答