一、概要
名字空间是一种描述逻辑分组的机制。也就是说,如果有一些声明按照某种准则在逻辑上属于同一个集团,就可以将它们放入同一个名字空间,以表明这个事实。名字空间就是为了表示逻辑结构。同时也避免了名字冲突。
名字空间的声明和定义:
namespace namespace-name {
}
PS:只有名字空间的声明定义与函数的定义后是不用分号;的,其余的都是要带分号的。
二、使用声明和使用指令
int main() {
std::cout << "Hello World" << std::endl;
std::cout << "Come On" << std::endl;
return 0;
}
如果像上面那样写,很令人厌烦。有两种方式可以解决这种烦恼。
(1)使用声明:
int main() {
using std::cout;
using std::endl;
cout << "Hello World" << endl;
cout << "Come On" << endl;
return 0;
}
使用声明,可以声明你想要的东西。
(2)使用指令
int main() {
using namespace std;
cout << "Hello World" << endl;
cout << "Come On" << endl;
return 0;
}
使用指令,则把该名字空间下的所有名字都变成可用的。
全局性的使用指令是一种完成转变的工具,在其他方面最好避免使用。在一个名字空间里的使用指令是一种名字空间的组合工具。在一个函数里可以安全地讲使用指令作为一种方便的记法方式。
三、名字空间的组合
namespace Stack {
void create();
void push(char *data);
char *pop();
int length();
} //在其他地方实现。
namespace Employee {
using namespace Stack;
void init() {
create();
}
void insert(char *name) {
push(name);
}
char* get_employee() {
return pop();
}
}
名字空间的组合也是一种设计,设计理念类似于类的组合。
四、多重界面
多重界面可以提供给用户不同的借口,而用户不用关心其底层是怎么实现的。
例子:
str1.h
#ifndef STR1_H_INCLUDED
#define STR1_H_INCLUDED
namespace My_String {
void init();
int length();
void set_string(char *data);
void print_string();
}
#endif // STR1_H_INCLUDED
str2.h
#ifndef STR2_H_INCLUDED
#define STR2_H_INCLUDED
namespace My_String {
void init();
int length();
}
#endif // STR2_H_INCLUDED
实现:strImpl.cpp
#include "str1.h"
#include <iostream>
namespace My_String {
char *buf = new char[200];
}
void My_String::init() {
strcpy(My_String::buf,"hello world");
}
int My_String::length() {
return strlen(My_String::buf);
}
void My_String::print_string() {
std::cout << buf << std::endl;
}
void My_String::set_string(char *data) {
char *tem = (char*)malloc(strlen(data) + 1);
strcpy(tem,data);
delete buf;
buf = tem;
}
str1.h和str2.h使用的都是My_String的名字空间,但提供给外界的接口是不一样的。
测试:
#include <iostream>
#include "str1.h" //包含的是str1
using namespace std;
int main() {
My_String::init();
char *pc = "my pc";
My_String::set_string(pc);
cout << My_String::length() << endl;
My_String::print_string();
return 0;
}
#include <iostream>
#include "str2.h"
using namespace std;
int main() {
My_String::init();
char *pc = "my pc";
My_String::set_string(pc); //错误,str2没提供这个接口
cout << My_String::length() << endl;
My_String::print_string(); //错误,str2没提供这个接口
return 0;
}
五、无名名字空间与名字空间别名
有时,将一组声明包裹在一个名字空间里就是为了避免可能的名字冲突。这样做的目的只是保持代码的局部性,而不是为用户提供界面。
noname.h
namespace {
int a;
double f(){};
}
void g() {
f();
}
无名名字空间有一个隐含的使用指令的。上面的代码相当于。
namespace $$${
int a;
double f(){};
}
using namespace $$$;
void g() {
f();
}
但不能在noname.h之外使用到这个无名名字空间里的东西了。例如:
#include "noname.h"
void h() {
a = 5; //错误,a不是全局变量,已经被包含在无名的名字空间中了。
}
如果名字空间的名字太长,我们可以给他取个别名。
例如:
namespace SomeOne_Union_Shit {
char *shit;
.....
}
namespace SomeOne = SomeOne_Union_Shit;
SomeOne::shit = "hello";
六、组合与选择
namespace His_lib {
void f() { cout << "his f" << endl; }
void g() { cout << "his g" << endl; }
}
namespace Her_lib {
void f() { cout << "her f" << endl; }
void g() { cout << "her g" << endl; }
}
namespace My_lib {
using namespace His_lib;
using namespace Her_lib;
using His_lib::f; //偏向His_lib的方式解析潜在的冲突
using Her_lib::g; //偏向Her_lib的方式解析潜在的冲突
void h() {
f(); // his f
g(); // her g
}
}
七、名字空间与重载,以及其开放性。
重载可以跨名字空间工作的。
namespace His_lib {
void f(int i) { cout << "his f" << endl; }
}
namespace Her_lib {
void f(char c) { cout << "her f" << endl; }
}
namespace My_lib {
void g() {
f(3); //his f
char c = 'a';
f(a); //her f
}
}
名字空间是开放的。一个名字空间的定义可以分布到多个头文件和源代码文件里。名字空间的开放性使我们可以通过展示名字空间不同部分的方式,为不同种类的用户提供不同的界面。
head1.h
namespace His_lib {
void f() ;
}
head2.h
namespace His_lib {
void g() ;
}
如果你只是向在文件里实现原先名字空间中已经声明的函数,则最好在此之前用名字空间的名字去修饰使用His_lib::的方式。
#include "head1.h"
namespace His_lib {
void His_lib::ff() {} //编译错误,His_lib没有声明这个。
void ff() {} //编译通过,在名字空间His_lib中引用了新的ff函数
}
一个名字空间应该:
[1]描述了一个具有逻辑统一性的特征集合。
[2]不为用户提供对无关特征的访问,使用封装。
[3]不给用户强加任何明显的记述负担。
参考书籍《C++程序设计语言》