代码之家  ›  专栏  ›  技术社区  ›  Scott

C++使用命名空间避免长路径

  •  2
  • Scott  · 技术社区  · 16 年前

    我仍然在学习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 回复  |  直到 14 年前
        1
  •  5
  •   Brian R. Bondy    16 年前

    您不需要为静态方法指定类名。

    using namespace Test;
    

    然后:

    int answerToEverything = A::foo();
    
        2
  •  10
  •   tpdi    16 年前

    在C++中,您必须仔细阅读编译器错误消息。

    注意,第一个错误是“错误:一个不是名称空间名称”。是的,A是一个类名。

    using namespace Foo; // brings in  all of foo;
    using Bar::Baz // brings in only Baz from Bar
    

    你想写:

    using Test::A;
    

    这有两个好处:它带来了一个供你使用的,并且没有带来所有其他的测试,这也很好,因为你应该只带来你需要的东西,这样就不会意外地依赖于你没有意识到你所依赖的东西。

    但是,由于foo在a中是静态的,您仍然需要显式地引用a::foo。(除非您执行类似于编写一个转发到::foo的自由函数的操作;一般来说,如果您只是为了保存一些键入内容,那么这是一个坏主意。)

    有些人可能建议不要使用声明,而是完全限定所有名称。

    但这是(引用stroustrup的话)“乏味且容易出错”,这妨碍了重构:假设您完全符合使用类foomatic::stack的条件,然后管理层坚持在您即将投入生产之前,使用barmatic非常类似的stack类,因为barmatic刚刚收购了您的公司。

    如果你在任何地方都完全合格的话,你会做很多的grepping,希望你的regex是正确的。如果您使用了一个using声明,那么您可以对(希望是共享的)头文件进行修复。通过这种方式,using声明非常类似于“typedef int ourint”;或清单常量或const:“const int foo=1;”,因为它提供一个位置来更改引用了多个位置的内容。在每次使用时完全限定一个名称空间会失去这种好处。

    相反,如果您使用了using指令并引入了所有命名空间foomatic,那么您的grep可能会更加困难,如果说管理层坚持使用barmatic::foo,但是您仍然必须使用foomatic:baz,因为任何原因baz都是不可用的。

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

        3
  •  0
  •   Adam Rosenfield    16 年前

    不,你不可能以优雅的方式去做你想做的事情。你能做的最接近的事情就是创建一个宏或一个内联函数,它委托给你的函数。但是,这两个选项都相当难看,所以我不会发布任何代码示例。只需咬紧牙关并指定整个名称,或者重构代码,使静态方法只是全局函数。

        4
  •  0
  •   Terry G Lorber    16 年前

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

    std::cout << Test::A::foo() << std::endl;