合格碱基的名称查找 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
我的问题是:
- (1) 是如何工作的 - 虽然基地 class 的名称具体是
D::S
- (1) 和 (2) 都需要工作吗?
- 为什么
f()
中的 S s;
指的是 D::S
而不是 ::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 名称 S
是 D::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::S
是 S
的完全限定名称,因此它指的是同一类型,但使用非成员必须使用的 "full name"参考类型。
- Why does S s; inside f() refer to D::S and not ::S ?
因为像构造函数一样,f()
是 X
的成员,所以名称查找首先在 X
(及其基础 classes)的范围内查找,因此找到注入的 class 名称。它永远不会在全局范围内看到类型 ::S
,因为它发现名称 S
作为基 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
我的问题是:
- (1) 是如何工作的 - 虽然基地 class 的名称具体是
D::S
- (1) 和 (2) 都需要工作吗?
- 为什么
f()
中的S s;
指的是D::S
而不是::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 中声明的名称,因此 X
中的名称查找首先查看其自己的成员及其基 class ' 成员,然后在 X
之外的封闭范围内查找名称。因为注入的 class 名称 S
是 D::S
的成员,它在 X
中被发现,这就是 (1) 起作用的原因。类型 ::S
未找到,因为名称查找找到注入的 class 名称并且从不查找封闭范围(如果它 did 找到 ::S
代码无法编译,因为 ::S
不是 X
的基础 class).
作为类比,请考虑使用在 D::S
:
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::S
是 S
的完全限定名称,因此它指的是同一类型,但使用非成员必须使用的 "full name"参考类型。
- Why does S s; inside f() refer to D::S and not ::S ?
因为像构造函数一样,f()
是 X
的成员,所以名称查找首先在 X
(及其基础 classes)的范围内查找,因此找到注入的 class 名称。它永远不会在全局范围内看到类型 ::S
,因为它发现名称 S
作为基 class 的成员并停止查找。