玩转C++名字空间

来源:互联网 发布:网络访谈节目 编辑:程序博客网 时间:2024/06/13 14:57

一、概要

名字空间是一种描述逻辑分组的机制。也就是说,如果有一些声明按照某种准则在逻辑上属于同一个集团,就可以将它们放入同一个名字空间,以表明这个事实。名字空间就是为了表示逻辑结构。同时也避免了名字冲突。

名字空间的声明和定义:

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_INCLUDEDnamespace 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_INCLUDEDnamespace 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"    //包含的是str1using 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 fg();   // 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 fchar 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++程序设计语言》