0

考虑这段代码:

#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

我的问题是:

  • (1) 是如何工作的 - 我会认为基类的名称是D::S专门的
  • (1) 和 (2) 都需要工作吗?
  • 为什么S s;insidef()D::S而不是::S
4

1 回答 1

5

显然,在类的主体中,D::S名称S指的是自身。这称为“注入的类名”。你可以把它想象成有一个公共成员 typedef ,D::S它有自己的名字,S.

  • (1) 是如何工作的 - 我会认为基类的名称是 D::S

X派生自D::S,因为您在 的基类列表中这么说X

派生类可以访问基类中声明的名称,因此名称查找X首先查看它自己的成员及其基类的成员,然后在外部的封闭范围内查找名称X。因为注入的类名S是 的成员D::S,所以可以在 中找到X,这就是 (1) 起作用的原因。::S找不到类型,因为名称查找找到了注入的类名称,并且从不在封闭范围内查找(如果确实找到::S代码将无法编译,因为::S它不是 的基类X)。

作为一个类比,考虑使用在中声明的成员 typedef 的示例D::S

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

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

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

  • (1) 和 (2) 都需要工作吗?

是的。

(2) 之所以有效,是因为D::S它是完全限定的命名,S所以它引用相同的类型,但使用非成员必须使用的“全名”来引用该类型。

  • 为什么 S s; 在 f() 中指的是 D::S 而不是 ::S ?

因为和构造函数一样,f()是so name lookup 的成员,首先在(及其基类)X的范围内查找,从而找到注入的类名。它永远不会在全局范围内X看到该类型,因为它发现该名称是基类的成员并停止查找。::SS

于 2015-06-16T23:12:16.607 回答