C++命名空间
命名空间是为了防止名字冲突提供了更加可控的机制。命名空间分割了全局命名空间,其中每个命名空间是一个作用域。通过在某个命名空间中定义库的名字,库的作者(以及用户)可以避免全局名字固有的限制。
命名空间的定义
命名空间由关键字 namespace 命名空间的名字(可以匿名后面讲)和由花括号括起来的生命和定义组成。
命名空间可以放 类、变量(及其初始化)、函数(及其定义)、模板和其他命名空间。
命名空间不能定义在函数或类的内部
namespace waorange
{
int a = 0;
class A
{
public:
void DoSomething() {}
};
void func();
void func1()
{
/**/
}
namespace other
{
int b = 0;
}
}
命名空间可以是不连续的
命名空间可以定义在几个不同的部分 例如我想去给上面的命名空间添加一部分内容:
namespace waorange
{
class B
{
public:
void DoSomething() {}
};
}
命名空间的三种访问方法
1.使用完全限定名:
waorange::A test;
test.DoSomething();
waorange::a = 10;
2.使用 using 声明, 以将一个标识符引入范围:
using waorange::A;
A test;
test.DoSomething();
3.使用 using 指令,以将命名空间中的所有内容引入范围:
using namespace waorange;
A test;
test.DoSomething();
a = 10;
全局命名空间
全局作用域中定义的名字就是定义在全局空间中。全局命名空间以隐式的方式声明,并且在所有程序中都存在。全局作用域中定义的名字被隐式的添加到全局命名空间中。
作用域运算符同样可以用于全局作用域的成员,因为全局作用域是隐式的,所以没有名字。下面的形式
::member_name
表示全局命名空间中的一个成员
嵌套命名空间
可以嵌套命名空间。 嵌套命名空间具有对其父级成员的非限定访问权限,而父成员不具有对嵌套命名空间的非限定访问权限,如下面的示例所示:
namespace NestNamespace
{
void Func();
namespace Nest
{
void test()
{
Func();
}
}
}
在外面访问内部嵌套的命名空间 NestNamespace::Nest::test();
命名空间别名
命名空间可以起别名
namespace alias = waorange;
alias::func1();
namespace another_name = alias;
another_name::func1();
namespace another_name2 = waorange;
another_name2::func1();
可以起多个别名
匿名或未命名的命名空间
namespace
{
int MyFunc(){}
}
这称为未命名的命名空间或匿名命名空间,在你想要使变量声明对于其他文件中的代码不可见(即 为它们提供内部链接),而不必创建已命名的命名空间时非常有用。 同一文件中的所有代码都可以看到未命名的命名空间中的标识符,但这些标识符以及命名空间本身在该文件外部不可见。
内联命名空间 (C++ 11)
以下转自https://msdn.microsoft.com/zh-cn/library/5cb46ksf.aspx
与普通嵌套命名空间不同,内联命名空间的成员会被视为父命名空间的成员。 这一特性使针对重载函数的依赖于参数的查找可以对父命名空间和嵌套内联命名空间中具有重载的函数起作用。 它还可让你在内联命名空间中声明的模板的父命名空间中声明专用化。 下面的示例演示在默认情况下,外部代码如何绑定到内联命名空间:
//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 的客户端代码将自动绑定到新代码。 通过使用指向包含该代码的嵌套命名空间的完全限定路径,选择使用较旧版本的客户端仍可以对其进行访问。
Inline 关键字必须应用到编译单元中命名空间的第一个声明中。
下面的示例演示一个接口的两个版本,每个版本位于一个嵌套命名空间中。 通过 v_10 接口对 v_20 命名空间进行了某些修改,且该命名空间被标记为内联。 使用新库并调用 Contoso::Funcs::Add 的客户端代码将调用 v_20 版本。 尝试调用 Contoso::Funcs::Divide 的代码现在将获取一个编译时错误。 如果它们确实需要该函数,则仍可以通过显式调用 Contoso::v_10::Funcs::Divide 访问 v_10 版本。
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);
T Subtract(T a, T b);
T Multiply(T a, T b);
std::vector<double> Log(double);
T Accumulate(std::vector<T> nums);
};
}
}
参考:
Stanley B. Lippman 《C++ Primer(中文版)(第5版)》
https://msdn.microsoft.com/zh-cn/library/5cb46ksf.aspx