C++你所不知道的命名空间

我们每天都在用using namespace std;但你对命名空间了解多少?

这是个啥?

命名空间是一种机制,用来把单个标识符下存在大量有逻辑联系的程序实体组合到一起,并以此标识符作为此组群的名字。
换一种说法,就是一个集合,其关键字就是命名空间的名字

using namespace name
{
	/* code */
} ;// namespace name

相关的几个概念(这三个作用域逐次减小)

  • 声明域(declaration region):声明标识符的区域
  • 潜在作用域(potential scope):从声明点开始,到声明域末尾的区域。(因为C++是先声明后使用的原则,所以声明点之前的声明域中,标识符是不能用的
  • 作用域(scope):即标识符对程序可见的范围,即真正在使用的范围
    CAUTION:MS的MFC(微软基础类库)中没有使用命名空间,但.NET有很多使用

定义命名空间

命名空间可以定义有名的和无名的(就像你定义一个struct结构体一样)
结合一个小例子:

namespace Outer
{
	int i;										// 命名空间Outer的成员i的内部定义

	namespace Inner								// 子命名空间Inner的内部定义
	{
		void Fun1() { i++; }					// i为 Outer::i
		int i;
		void Fun2() { i++; }					// Inner::i
		void Fun3();
		} // namespace Inner
		void Fun1();
		// namespace Inner2;					// 错误,不能 声明 (而非定义)子命名空间
} // namespace Outer

void Outer::Fun1()
{
	i--;
}

void Outer::Inner::Fun3()
{
	i--;
}
  • 不能在命名空间的定义中声明(另一个嵌套的)子命名空间,只能定义子命名空间
  • 命名空间必须定义在头文件中,所以记得新建一个 .h 文件哦
  • 命名空间是开放的,这也就意味着可以随时将新的成员名称加入到已有的命名空间中去,但规则嘛,就是不能直接使用命名空间名::成员名的形式,而必须先在命名空间的定义中声明,方法是多次声明和定义同一命名空间,每次添加新成员
  • 还可以组合现有的命名空间(使用using)
    For example:
namespace sample
{
	int i;
	void Fun1();
}												// 现在有成员i, Fun1()
namespace sample								// 重新定义命名空间sample
{
	int j;
	void Fun2()
}												// 现在有成员i, Fun1(), j, Fun2()
namespace sample1
{
	using namespace sample;
	void Fun3();
}												// 组合命名空间

使用它!

  • 使用作用域运算符“: :“ (就像你对类成员所做的那样)
  • 使用using指令
    • 标准C++库(不包括标准C库)中所包含的所有内容(包括常量,变量,结构,类和函数, etc.)都被定义在命名空间std(standard标准)中了,但预编译(#include) 部分应包含不带.h的标准头文件(例如#include <iostream>)然后再using namespace std;
    • using自定义的命名空间:
      using namespace 命名空间名[ ::子命名空间名1…… ]
      当只有一个字空间时,可以略去不写 [ ]
      using namespace Outer::Inner;
    • 要写子命名空间而不是只写(也不用/不能额外写)基命名空间,不然很有可能引起名称冲突
    • 剩下的就像使用类一样
  • 使用using声明
    • using 命名空间名::[子命名空间名::子子……]成员名;
    • 用处相当于对于单独一个成员免去每一次都写作用域运算符的麻烦,但该命名空间下的其他成员依然要依靠作用域运算符来定位
  • using指令和using声明的比较
    • using指令使用后,可以一劳永逸,它对整个命名空间所有成员都有效;但using声明却必须对不同成员分别声明
    • 但一般来说,using声明会更加安全。因为using声明只会导入指定的名称,如果改名称与局部名称冲突,编译器会报错。而using指令导入的,包括那些根本用不到的名称,且如果其中有 名称与局部名称冲突,编译器不会发出任何警告信息,而是仅仅用局部名称覆盖命名空间中的同名成员
    • Conclusion:虽然使用命名空间的方法有多种可供选择,但不能贪图方便而一味使用using指令,那样就背离了设计命名空间的初衷,也失去了命名空间本应有的防止名称冲突的功能
发布了4 篇原创文章 · 获赞 3 · 访问量 171

猜你喜欢

转载自blog.csdn.net/weixin_45494811/article/details/104031808