一、前言
实际的软件开发过程中,一个程序往往由多名程序员共同开发。不同程序员在开发过程中都会使用大量的变量和函数,这个时候就会出现变量或函数的命名冲突。虽然每个人的代码都没有问题,但将它们结合到一起就可能会因为命名冲突而出现错误。
在没有命名空间的C语言中,如果出现了命名冲突,那只能在所有人写过的代码中,找出那些命名冲突的变量或函数,进行修改。
因为李四经常写出和张三相同的变量名和函数名,没少挨张三的打。公司为了李四的生命安全着想,决定让他们一起学习有命名空间(namespace)的C++
!
二、命名空间
1、命名空间的定义
在C/C++
中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,
以避免命名冲突或名字污染,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围,命名空间中的所有内容都会局限于该命名空间这个范围之中。
定义命名空间,需要使用到namespace
关键字,后面跟命名空间的名字,然后接一对{}
即可,{}
中即为命名空间的成员。
Ⅰ、正常定义
namespace name1
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
这段代码中name1
是该命名空间的名字,它里面可以包含变量、函数、类、typedef
、#define
等,最后用{ }
包围起来。
Ⅱ、嵌套定义
命名空间是可以嵌套定义的,即在一个命名空间中定义另外一个命名空间。
namespace name1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace name2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
Ⅲ、不连续定义
同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
在test.h
中有如下定义:
namespace name3
{
int Add(int x, int y)
{
return x + y;
}
}
在test.cpp
中有如下定义:
namespace name3
{
int Mul(int left, int right)
{
return left * right;
}
}
由于两个命名空间的名字相同,所以在编译器严重,这两段可以视为如下代码:
namespace name3
{
int Add(int x, int y)
{
return x + y;
}
int Mul(int left, int right)
{
return left * right;
}
}
2、命名空间的使用
命名空间的使用有如下三种方式:
- 加命名空间名称及域解析操作符
- 使用
using
将命名空间中某个成员引入 - 使用
using namespace
命名空间名称 引入
Ⅰ、域解析操作符
::
是一个新符号,称为域解析操作符,在C++
中用来指明要使用的命名空间。
namespace name1
{
int a = 1;
int b = 2;
int Add(int left, int right)
{
return left + right;
}
}
int main()
{
printf("%d\n", name1::a); //使用name1中的变量a
return 0;
}
Ⅱ、using
引入空间成员
使用using
这个新关键字引入空间中的成员。
namespace name1
{
int a = 1;
int b = 2;
int Add(int left, int right)
{
return left + right;
}
}
using name1::b;//引入了name1命名空间中的b成员
int main()
{
printf("%d\n", name1::a);
printf("%d\n", b);
return 0;
}
Ⅲ、using namespace
引入空间所有成员
namespace name1
{
int a = 1;
int b = 2;
int Add(int left, int right)
{
return left + right;
}
}
using namespace name1;
int main()
{
printf("%d\n", a);
printf("%d\n", b);
Add(10, 20);
return 0;
}
三、std
命名空间
1、std的来历
std
是英文单词S tan dard 的缩写,意思是“标准命名空间”。
它是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中。
因为早期的 C++ 还不完善,不支持命名空间,没有自己的编译器,而是将 C++ 代码翻译成C代码,再通过C编译器完成编译。所以早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来又开发了命名空间这一功能,就将类、函数、宏等都统一纳入在std
命名空间下,为了和C的头文件区分,也为了正确使用命名空间。
注意:为了避免头文件重名,C++ 库也对头文件的命名做了调整,去掉了后缀.h,所以C语言的头文件,在c++中依旧存在,但在每个名字前还要添加一个c字母,并且去掉.h所以C语言的stdio.h
变成了cstdio
,stdlib.h
变成了cstdlib
。
比如C语言中我们使用printf
函数需要这样写:
#include<stdio.h>
int main ()
{
printf("hello world !");
return 0;
}
而C++中我们使用printf
函数则需要这样写:
#include<cstdio>
using namespace std;
int main()
{
printf("hello world !");
return 0;
}
2、std
的使用惯例
- 在日常练习中,建议直接
using namespace std
即可,这样就很方便。 using namespace std
展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对
象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模
大,就很容易出现。所以建议在项目开发中使用,像std::cout
这样使用时指定命名空间 + using std::cout
展开常用的库对象/类型等方式。
四、总结
1、命名空间的三种定义方式
- 正常定义。
- 嵌套定义。
- 不连续定义。
2、命名空间的三种使用方法
- 域解析操作符
::
。 using
关键字部分引入。using namespace
全部引入。
3、 std
使用注意
- 区分日常使用和项目开发使用。