通过重复对象名称来调用静态方法
我有一个单身人士:
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();