2

我仍在学习 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

4

4 回答 4

10

在 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 刚刚收购了你的公司。

如果你在任何地方都完全合格,你会做很多 grepping,希望你的正则表达式是正确的。如果你使用了 using 声明,你可以对你的(希望是共享的)头文件进行修复。这样,使用声明很像“typedef int ourInt;”。或一个清单常量或 const:“const int FOO = 1;”,因为它提供了一个地方来更改引用到许多地方的东西。在每次使用时完全限定命名空间会带走这种好处。

相反,如果您使用了 using 指令并引入了所有命名空间 FooMatic,那么您的 grep 可能会更加困难,如果说管理层坚持使用 BarMatic::Foo 但您仍然必须使用 FooMatic:Baz,Baz 的 BarMatic 等价物用于无论什么原因无法使用。

因此,一次引入一种类型(类、函数、常量)通常是最灵活的,也是最好地保护自己免受不可避免但未知的变化的方法。与大多数编码一样,您希望在保持足够粒度的同时尽量减少繁琐的重复。

于 2009-04-02T02:47:53.150 回答
5

没有办法绕过它,您需要为静态方法指定类名。

using namespace Test;

然后:

int answerToEverything = A::foo();
于 2009-04-02T02:44:41.723 回答
0

不,不可能以任何优雅的方式做你想做的事情。你能做的最接近的事情是创建一个宏或一个内联函数来委托给你的函数。然而,这两种选择都相当难看,所以我不打算发布任何代码示例。只需硬着头皮指定整个名称,或者重构代码,使静态方法只是全局函数。

于 2009-04-02T02:47:11.623 回答
0

不要成为“使用命名空间”的滥用者。使用这些命名空间!

std::cout << Test::A::foo() << std::endl;
于 2009-04-02T03:45:56.053 回答