题
我仍在学习 C++,之前从未真正创建过自己的命名空间。我正在用它们进行实验,虽然我完成了大部分工作,但有一件事我似乎仍然无法做到。我希望能够在类中调用静态方法,而无需输入类似的内容 NameOfClass::method
. 。我认为代码应该如下所示,但无法编译:
文件 A.h
,
namespace Test
{
class A
{
public:
static int foo() { return 42; }
};
}
文件 main.cpp
,
#include <iostream>
#include "A.h"
using namespace std;
using namespace Test::A;
int main()
{
cout << foo() << endl;
return 0;
}
编译器给我:
main.cpp:6: error: ‘A’ is not a namespace-name
main.cpp:6: error: expected namespace-name before ‘;’ token
main.cpp: In function ‘int main()’:
main.cpp:10: error: ‘foo’ was not declared in this scope
是否可以在不打字的情况下完成我想做的事情 A::foo
?
解决方案
没有办法解决这个问题,您需要为静态方法指定类名。
using namespace Test;
然后:
int answerToEverything = A::foo();
其他提示
在 C++ 中,您/尤其是/必须仔细阅读编译器错误消息。
请注意,第一个错误是“错误:‘A’不是命名空间名称”。确实如此,A 是一个类名。
using namespace Foo; // brings in all of foo;
using Bar::Baz // brings in only Baz from Bar
你想写:
using Test::A;
这有两件好事:它引入了A供你使用,并且它没有引入Test的所有其余部分,这也很好,因为你应该只引入你需要的东西,以免意外地依赖于你没有意识到的东西你所依赖的。
但是,由于 foo 在 A 中是静态的,因此您仍然必须显式引用 A::foo 。(除非你做了一些事情,比如编写一个转发到 A::foo; 的自由函数)一般来说,如果您只是为了节省一些打字量,那么这是一个坏主意。)
有些人可能建议根本不使用 using 声明,而是完全限定所有名称。
但这是(引用 Stroustrup 的话)“乏味且容易出错”,并且它妨碍了重构:假设您完全限定了 FooMatic::Stack 类的每次使用,然后管理层坚持在您即将投入生产之前使用 BarMatic 非常相似的 Stack 类,因为 barMatic 刚刚收购了您的公司。
如果您在所有地方都完全合格,您将进行大量的 grep 操作,希望您的正则表达式是正确的。如果您使用了 using 声明,则只需修复您的(希望是共享的)头文件即可。这样,使用声明就像是“ typedef int insint”;或明显常数或const:“const int FOO = 1;”,因为它提供了一个地方来更改引用到许多地方的内容。每次使用时完全限定名称空间会消除这一好处。
相反,如果您使用 using 指令并引入所有名称空间 FooMatic,那么您的 grep 可能会更加困难,如果说管理层坚持使用 BarMatic::Foo 但您仍然必须使用 FooMatic:Baz,BarMatic 相当于 Baz 的无论什么原因都无法使用。
因此,一次引入一种类型(类、函数、常量)通常是最灵活的,也是最好的保护自己免受不可避免但未知的变化影响的方法。与大多数编码一样,您希望最大限度地减少繁琐的重复,同时保持足够的粒度。
不,不可能以任何优雅的方式做你想做的事情。您能够做的最接近的事情是创建一个委托给您的函数的宏或内联函数。然而,这两种选择都相当难看,所以我不会发布任何代码示例。只需硬着头皮指定整个名称,或者重构代码,使静态方法只是全局函数。
不要成为“使用命名空间”的滥用者。使用这些命名空间!
std::cout << Test::A::foo() << std::endl;