一、引子
一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,不可避免地会出现变量名或函数名的命名冲突。当所有人的代码测试通过,结合在一起时就有可能会造成命名冲突。
例如:小李和小韩都参与了一个文件管理系统的开发,它们都定义了一个全局变量fp,用来指明当前打开的文件,当他们代码结合在一起时。很明显,编译器会提示fp重复定义。
为了解决合作开发的命名冲突的问题,C++引入了命名空间(namespace)的概念。
诸如:
namespace Li//李定义的变量fp
{
FILE *fp;
}
namespace Wang//王定义的变量fp
{
FILE *fp;
}
namespace是C++关键字,用来定义一个命名空间。语法格式为:
namespace <name>{
//varibles,functions,classes....
}
二、如何使用
用以下例子说明:
#include <iostream.h>
using namespace std;//这里使我用了全局标准的命名空间
namespace NSA//NSA的命名空间
{
int a = 10;
}
namespace NSB//NSB的命名空间
{
int a = 20;
namespace NSBA//NSB嵌套定义了一个NSBA 表明NSBA域只能为NSB所有
{
struct stu//NSBA域里面有一个C++结构体
{
char data[20];
int a;
};
int a = 1997;//和一个和NSB同名的整形变量a
}
}
namespace NSC
{
int a = 827;
}
//如何初始化和使用它们呢?
//如下所示:
main(void)
{
cout << NSA::a <<endl;
cout << NSB::a <<endl;
NSB::NSBA::stu Stu = {"hello world", 1997};
cout << Stu.data << Stu.a <<endl;
cout << NSC::a <<endl;
return 0;
}
编译,运行:
其中 “::” 是一个域解析操作符,在后面学习中会经常看到。除了使用特定人的命名空间外,比如说类体外定义类体中声明的函数也需要用到这个符号。
以上代码是用于测试的,在编译过程中 遇到了警告等问题。我这里特地把#include <iostream> ---新版头文件用旧版头文件#include<iostream.h>来代替,因为现在我们还没接触到标准命名空间std。
解决方法
使用全局的using namespace std; 时, 头文件必须用新版头文件代替。
编译成功了。
除了直接使用域解析操作符意外,还可以采用using关键字声明;例如:
using Li::fp;
fp = fopen("hello.txt", "wb+");
Wang::fp = fopen("world.txt", "r");
他的意思是using声明后的程序中如果出现了未指明的命名空间就默认使用Li的命名空间;但若是要用小王定义的fp,还是仍然需要使用Wang::fp。
如果命名空间Li中还定义了其他的便来给你,那么同样具有fp变量的同等效果。
命名空间内不仅可以声明或定义变量,对于其他能在命名空间以外声明或定义的名称,同样也能在命名空间内部进行定义,例如:类、函数、typedef、#define等都可以出现在命名空间中。
由命名空间创建的对象也是只能为改命名空间所有者所用。这样,在函数內使用就有了两种方式:
1.usingname space xia;//全局作用域
2.int add(){ using namespace xia; ...}//局部作用域
3.xia::<class name> <object name>//使用域名解析操作符
C++命名空间比较复杂,我在这里学习的仅仅是冰山一角。后面在学习中我会一步一步的摸索与学习。
三、C++头文件和标准命名空间std
以上是命名空间的简介,也是使用标准命名空间的基础知识。标准命名空间也是说在后期的C++编码中经常会使用到的代码了:
using namespace std;
早期的C++是在C语言的基础上开发的,早期还不太完善,更不支持命名空间,没有自己的编译器,而是将C++代码翻译成C代码,再通过C编译器完成编译的。
此外吗,C++还开发了一些新的库,增加了自己的头文件,诸如:
iostram.h 用于控制台的输入输出
fstream.h 用于文件操作
complex.h用于复数计算
后来C++引入了命名空间,计划重新将库,类,函数,宏等都纳入一个命名空间中。这个命名空间的名字就是std。---标准命名空间
为了避免重名,C++库对头文件名称也做了调整,去掉了后缀 .h 。所以老式的iostream.h变成了新的iostream。原来C语言中的stdio.h
变成了cstdio; stdlib.h变成了cstdlib。
如何使用:
#include <cstdio>
int main()
{
std::printf("hello world\n");
return 0;
}
#include <cstdio>
int main()
{
printf("hello world\n");
return 0;
}
这两种方式,在编译器中都能通过,也就是说大部分编译器在实现时没有严格遵循C++标准,程序员可以使用std,也可以不使用std。
只不过,第一种标准的,第二种不标准。
标准命名空间的作用域:
#include <cstdio>
#include <iostream>
#include <string>
int Add(int n)
{
using namespace std;//作用域Add()
int sum = 0;
for(int i=0; i<=n; i++)
{
sum += i;
}
cout<<"n = "<<n<<" "<<endl;
return sum;
}
int main(void)
{
using namespace std;//作用域main()
string str = "hello";//定义字符串变量
int age = 1;
cout<<"input string:"<<endl;
cin>>str;
cout<<"input age:"<<endl;
cin>>age;
//std::printf("%s %d\n", str, age);
cout<<"str is "<<str<<" age is "<<age<<endl;//使用局部标准命名空间
cout<<"result = "<<Add(age)<<" "<<endl;
return 0;
}
一旦使用了标准命名空间,新版支持的标准c库就不能用std::printf()使用了编译器G++不会报错,会报警告 运行时将出现非法指令的错误std::printf("%s %d\n", str, age);
//使用标准命名空间 但是标准写法printf("%s %d\n", str, age);//不使用std 是不标准的写法 但编译器不会报错。
using namespace std; 它声明了命名空间std,后续如果有未指定的命名空间符号那么默认使用std。诸如:cin、cout都位于命名空间std。
四、总结
在很多例子中,std是直接声明在全局的,是为了后面使用函数方便;但是在中大型项目开发中是不被推荐的,这样做增加命名冲突的风险。