C++编程中的命名空间基本知识讲解
命名空间是一个声明性区域,为其内部的标识符(类型、函数和变量等的名称)提供一个范围。命名空间用于将代码组织到逻辑组中,还可用于避免名称冲突,尤其是在基本代码包括多个库时。命名空间范围内的所有标识符彼此可见,而没有任何限制。命名空间之外的标识符可通过使用每个标识符的完全限定名(例如 std::vector<std::string> vec;)来访问成员,也可通过单个标识符的 using 声明 (using std::string) 或命名空间中所有标识符的 using 指令 (C++) (using namespace std;) 来访问成员。头文件中的代码应始终使用完全限定的命名空间名称。 namespace ContosoData { class ObjectManager { public: void DoSomething() {} }; void Func(ObjectManager) {} } 使用完全限定名: ContosoData::ObjectManager mgr; mgr.DoSomething(); ContosoData::Func(mgr); 使用 using 声明,以将一个标识符引入范围: using WidgetsUnlimited::ObjectManager; ObjectManager mgr; mgr.DoSomething(); 使用 using 指令,以将命名空间中的所有内容引入范围: using namespace WidgetsUnlimited; ObjectManager mgr; mgr.DoSomething(); Func(mgr); using 指令 //contosoData.h #pragma once namespace ContosoDataServer { void Foo(); int Bar(); } contosodata.cpp 中的函数实现应使用完全限定名,即使将一个 using 指令放置于文件的顶部也是如此: #include "contosodata.h" using namespace ContosoDataServer; void ContosoDataServer::Foo() { //no qualification because using directive above Bar(); } int ContosoDataServer::Bar(){return 0;} 可以在单个文件中的多个块中声明命名空间,也可在多个文件中声明命名空间。编译器在预处理过程中将各部分联接在一起,产生的命名空间中包含所有部分中声明的所有成员。一个相关示例是在标准库中的每个头文件中声明的 std 命名空间。 // defining_namespace_members.cpp // C2039 expected namespace V { void f(); } void V::f() { } // ok void V::g() { } // C2039,g() is not yet a member of V namespace V { void g(); } } 当跨多个头文件声明命名空间成员,并且未以正确的顺序包含这些标头时,可能出现此错误。 namespace ContosoDataServer { void Foo(); namespace Details { int CountImpl; void Ban() { return Foo(); } } int Bar(){...}; int Baz(int i) { return Details::CountImpl; } } 普通嵌套命名空间可用于封装不属于父命名空间的公共接口的一部分的内部实现详细信息。 //Header.h #include <string> namespace Test { namespace old_ns { std::string Func() { return std::string("Hello from old"); } } inline namespace new_ns { std::string Func() { return std::string("Hello from new"); } } } #include "header.h" #include <string> #include <iostream> int main() { using namespace Test; using namespace std; string s = Func(); std::cout << s << std::endl; // "Hello from new" return 0; } 下面的示例演示如何在内联命名空间中声明的模板的父命名空间中声明专用化: namespace Parent { inline namespace new_ns { template <typename T> struct C { T member; }; } template<> class C<int> {}; }
可以将内联命名空间用作版本控制机制,以管理对库的公共接口的更改。例如,可以创建单个父命名空间,并将接口的每个版本封装到嵌套在父命名空间内的其自己的命名空间中。保留最新或首选的版本的命名空间限定为内联,并因此以父命名空间的直接成员的形式公开。调用 Parent::Class 的客户端代码将自动绑定到新代码。通过使用指向包含该代码的嵌套命名空间的完全限定路径,选择使用较旧版本的客户端仍可以对其进行访问。 namespace Contoso { namespace v_10 { template <typename T> class Funcs { public: Funcs(void); T Add(T a,T b); T Subtract(T a,T b); T Multiply(T a,T b); T Divide(T a,T b); }; } inline namespace v_20 { template <typename T> class Funcs { public: Funcs(void); T Add(T a,T b); std::vector<double> Log(double); T Accumulate(std::vector<T> nums); }; } }
namespace a_very_long_namespace_name { class Foo {}; } namespace AVLNN = a_very_long_namespace_name; void Bar(AVLNN::Foo foo){ } 匿名或未命名的命名空间 namespace { int MyFunc(){} } 这称为未命名的命名空间或匿名命名空间,在你想要使变量声明对于其他文件中的代码不可见(即为它们提供内部链接),而不必创建已命名的命名空间时非常有用。同一文件中的所有代码都可以看到未命名的命名空间中的标识符,但这些标识符以及命名空间本身在该文件外部(或更准确地说,在翻译单元外部)不可见。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |