通过重复对象名称来调用静态方法
我有一个单身人士:
struct foo { static foo& instance() { static foo f; return f; } };
当重新安排一些代码时,我以“错误”结束了这个陈述:
foo::foo::instance()
但是我的编译器(gcc 4.7)认为这是正确的。 实际上,甚至foo::foo::foo::instance()
也会编译。 为什么?
这是由于“注入名称” – 这意味着如果foo
是一个类名称,并且同样的名字“foo”也被注入到类的范围内,这就是为什么你的代码工作。 这是100%符合标准。
下面是一个有趣的例子,它显示了这个function的好处:
namespace N { //define a class here struct A { void f() { std::cout << "N::A" << std::endl; } }; } namespace M { //define another class with same name! struct A { void f() { std::cout << "M::A" << std::endl; } }; struct B : N::A //NOTE : deriving from N::A { B() { A a; af(); //what should it print? } }; }
af()
应该调用什么? 什么是一个types? 是M::A
还是N::A
? 答案是, N::A
,而不是M::A
- 在线演示
这是因为名字注入, N::A
在B
的构造函数中是没有资格的 。 它也隐藏 M::A
,它仍然不在B
的范围之内。 如果你想使用M::A
,那么你必须写M::A
(或更好::M::A
)。
由于[class]/2
:
在看到类名后立即声明一个类名 。 类名也被插入到类本身的范围中; 这被称为注入类的名称 。
所以foo::foo
是一个注入类名,表示foo
本身。
其实它有点复杂:根据[class.qual]/2
, foo::foo
单独表示foo::foo
的构造函数。 为了表示一个类,它应该在struct
前面(使它具有详细的types说明符 ),或者跟在::
:(使它成为一个嵌套的名称说明符 – 这是你的情况) 说明符 (例如, struct bar : foo::foo {};
)。
正如其他答案所述,原因是名称注入。 对我来说,主要的用例如下
struct B1 { void f(){} }; struct B2 { void f(){} }; struct D : B1, B2 { } int main() { D obj; obj.f(); }
main
调用f
是不明确的,不会编译。 具体的方式是一个合格的电话,即
obj.B1::f();