合格碱基的名称查找 class

Name lookup of qualified base class

考虑这段代码:

#include <iostream>

namespace D
{
    struct S { S(){std::cout << "D::S\n";} };
}

struct S { S(){std::cout << "S\n";} };

struct X: D::S
{
    X(): S() {}        // (1)
    // X(): D::S() {}  // (2)

    void f() { S s; }
};

int main() { X x; x.f(); }

g++ 的输出是:

D::S
D::S

我的问题是:

在 class D::S 的正文中,名称 S 显然指的是它自己。这叫做"injected class name"。你可以把它想象成 D::S 中有一个 public 成员 typedef,它有自己的名字,S.

  • How does (1) work - I would have though that the name of the base class is D::S specifically

X 派生自 D::S,因为您在 X.

的基础 class 列表中是这样说的

派生 class 可以访问基 class 中声明的名称,因此 X 中的名称查找首先查看其自己的成员及其基 class ' 成员,然后在 X 之外的封闭范围内查找名称。因为注入的 class 名称 SD::S 的成员,它在 X 中被发现,这就是 (1) 起作用的原因。类型 ::S 未找到,因为名称查找找到注入的 class 名称并且从不查找封闭范围(如果它 did 找到 ::S代码无法编译,因为 ::S 不是 X 的基础 class).

作为类比,请考虑使用在 D::S:

中声明的成员 typedef 的示例
namespace D {
  struct S {
    struct S { S(){std::cout << "D::S\n";} };
    typedef S AnotherName;
  };
}

struct X : D::S {
  X() : AnotherName() { }
};

之所以有效,是因为名称 AnotherName 在基 class 中找到,并且是基 class、D::S 类型的同义词。注入的 class 名称的工作方式类似,只是注入的名称是 class 自己的名称 S,而不是其他名称,例如 AnotherName.

  • Are (1) and (2) both required to work?

是的。

(2) 之所以有效,是因为 D::SS 的完全限定名称,因此它指的是同一类型,但使用非成员必须使用的 "full name"参考类型。

  • Why does S s; inside f() refer to D::S and not ::S ?

因为像构造函数一样,f()X 的成员,所以名称查找首先在 X(及其基础 classes)的范围内查找,因此找到注入的 class 名称。它永远不会在全局范围内看到类型 ::S,因为它发现名称 S 作为基 class 的成员并停止查找。