前言
我们在编写一些比较大的项目时,会出现很多的变量、函数、类,若不做处理,它们将全部存在于全局作用域中,这可能会导致很多冲突。尤其在多人合作编写项目时,不同的人可能会使用相同的名称,最后整合代码时,项目就会存在各种命名冲突或名字污染。
命名空间的出现就是为了减少这样的事情出现。它对标识符的名称进行了本地化,有效地避免了命名冲突或名字污染。
命名空间的定义
一般格式:
namesapce <命名空间的名字>
{
//命名空间的成员(可以是:变量/函数/类)
}
命名空间定义的一些小tips:
- 命名空间的名字:开发中一般用项目名字作为命名空间的名字
- 命名空间可嵌套定义
- 同名的命名空间:可在项目中定义多个同名的命名空间,编译器会将它们合并
举例说明
- [代码1] 命名空间一般的定义:Coconut是自定义命名空间的名字
namespace Coconut
{
int a = 0;
int b = 0;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
- [代码2] 命名空间的嵌套定义
namespace N1
{
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int c = 2;
int d = 3;
int Sub(int left, int right)
{
return left - right;
}
}
}
- [代码3] 不同文件下的多个同名命名空间,编译器会将其合并
//在test.h下有
namespace N1
{
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
}
//在test.cpp下有
namespace N1
{
int Mul(int left, int right)
{
return left * right;
}
}
//最终编译时相当于一个命名空间N1
namespace N1
{
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
int Mul(int left, int right)
{
return left * right;
}
}
命名空间的使用
命名空间中可以定义变量/函数/类型,那么我们该如何使用到命名空间中定义的成员呢?
下面是命名空间的三种使用方法:
- 直接使用:<命名空间名称>::<成员名>
- 引入目标成员后使用:using <命名空间名称>::<成员名>
- 引入整个命名空间后使用:using namespace <命名空间名称>
注意:
使用命名空间之前要在当前文件包含头文件,或定义命名空间。
举例说明
假设在test.h文件中定义了命名空间N1
//在test.h下有
namespace N1
{
int a = 6;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
}
- [代码一] 直接使用。采用<命名空间名称>::<成员名>的格式直接使用目标命名空间中的成员
#include<stdio.h>
//在使用N1之前包含N1所在的头文件
#include"test.h"
//在使用Coconut之前先定义
namespace Coconut
{
int a = 100;
int b = 0;
int Mul(int left, int right)
{
return left * right;
}
struct Node
{
struct Node* next;
int val;
};
}
//直接使用N1和Coconut中的成员
int main()
{
printf("%d\n", N1::a);//输出6
printf("%d\n", Coconut::a);//输出100
return 0;
}
- [代码二]引入成员后使用。注意引入后的成员的作用域将在所在文件中展开,类似于全局变量,局部变量的定义,这取决于你引入的位置,如果在函数中引用,它的作用域就是这个函数,类似地,如果在函数外使用它的作用域就是所在文档。
#include<stdio.h>
//在使用N1之前包含N1所在的头文件
#include"test.h"
//在使用Coconut之前先定义
namespace Coconut
{
int a = 100;
int b = 0;
int Mul(int left, int right)
{
return left * right;
}
struct Node
{
struct Node* next;
int val;
};
}
//引入目标成员后使用
using N1::a;
using N1::b;
using Coconut::Mul;
int main()
{
printf("%d\n", Mul(a, b));//输出6
printf("%d\n", Add(a, b));//未引入对应成员,编译错误!
return 0;
}
- [代码三]引入命名空间后使用。作用与引入成员后使用类似,相当于引入命名空间中的全部成员。
#include<stdio.h>
//在使用N1之前包含N1所在的头文件
#include"test.h"
//在使用Coconut之前先定义
namespace Coconut
{
int a = 100;
int b = 0;
int Mul(int left, int right)
{
return left * right;
}
struct Node
{
struct Node* next;
int val;
};
}
//引入命名空间后使用
using namespace N1;
//因为Coconut与N1中定义了同名成员
//若在同个位置展开N1与Counut会发生命名冲突,导致编译出错
//using namespace Coconut;
int main()
{
printf("%d\n", Add(a, b));//输出7
return 0;
}
命名空间与作用域
一个命名空间定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。
作者言:
新人小白,若文中有错,恳请留言指正。