【c++笔记一】"名字空间"(namespace)

来源:互联网 发布:canal mysql 编辑:程序博客网 时间:2024/06/05 14:25

2015年1月21日

寒假第一天,程序猿的第一天,减肥的第一天(瘦了两斤,鼓掌得意

学要有所得,既然今天学了一天,是该好好整理一下今天所学的内容。

菜鸟一枚,如有bug还望指点一二。

-------------------------------------------------------华丽的分割线---------------------------------------------------------------

名字空间(namespace

1.为什么需要名字空间呢?

假如你是月入上万的快递员蜀黍,有天你来到某某学校给小强送快递,可是一班有个小强,二班也有个小强。这小强怎么区分呢?
回到程序世界,一段程序中,可能有两个变量需要用到sum这个名字,除了改写成不同的sum(sum1或sum2)之外,我们还有什么方法呢?
啰嗦这么多,终于扯到namespace(名字空间)上来了。

2.什么是名字空间?

从字面意思我们就能理解,这是一个用来存放名字的空间,可能你还不太懂,我们下面看程序就知道了。
先给大家看一段最简单的c++程序,一定是每个初学者都会看到的代码:
#include <iostream>using namespace std;int main(){    cout<<"hello world"<<endl;    return 0;}
在第二行我们看见了我们看到了namespace这个单词,很多初学者肯定不知道这是干什么的。老师或许告诉你,不用管他干什么的,知道写上去就行了。读书最怕一知半解,我们接下来就来看看这到底是干什么的。

3.名字空间的作用:

(1)划分逻辑单元

比如,一班的小强和二班的小强不是同一个小强。
一个是一班的,一个是二班的。我们从逻辑上把他们放在了不同的两个班级中。
一班、二班就是我们定义的两个逻辑单元。

(2)避免名字冲突

由上可知,小强这个名字冲突了。
通过加上名字空间(一班或者二班),我们就能有效的区分,避免了同名带来的名字冲突。

4.怎样定义名字空间?

说了那么多,这到底怎么用呢?这里又有三个知识点:

(1)名字空间定义

好吧,我们动手敲代码来区分这两个小强吧。
#include <iostream>namespace Class1{    char xq[] = "我是一班的小强";}namespace Class2{    char xq[] = "我是二班的小强";}int main(){    std::cout<<Class1::xq<<std::endl;    std::cout<<Class2::xq<<std::endl;    return 0;}
ps:1.cout和endl这两个属于std这个名字空间
2.我们要使用名字空间的时候,可以用 "::"这个符号(下面我们会讲到)

运行这个程序你会发现,输出是不同的结果:
由此我们可以知道名字空间的定义方法了:
namespace 空间名{...}

(2)名字空间合并

我们再看这样一段代码:
#include <iostream>using namespace std;namespace Class1{    char xq[] = "我是一班的小强";}namespace Class2{char xq[] = "我是二班的小强";}namespace Class1{    void show(){        cout<<xq<<endl;    }}namespace Class2{    void show(){        cout<<xq<<endl;    }}int main(){Class1::show();Class2::show();return 0;}
我们可以看到,show()这个函数和xq字符串并没有定义在一起,而是分开定义,但是同时属于一个名字空间。
运行结果同上,节省空间不展示了。
这就是我们所说的名字空间的合并,只要名字空间一样无论你在哪里定义,最后都会合并在一起。

(3)声明定义分开

学过c或者c++对的同学知道,声明和定义其实是可以分开的。先写声明,后定义。那名字空间可以吗?
行不行,写出来就知道了。
#include <iostream>using namespace std;namespace Class1{char xq[] = "我是一班的小强";void show();} // 声明namespace Class2{char xq[] = "我是二班的小强";void show();} //声明int main(){Class1::show();Class2::show();return 0;}namespace Class1{void show(){    cout<<xq<<endl;}} // 定义namespace Class2{void show(){    cout<<xq<<endl;}} //定义
运行结果同样一样,果然和我们以前学的声明定义一样,是可以分开的写的。

5.怎样使用名字空间?

既然我们已经定义好了名字空间了,怎么使用它呢?上面的代码我们已经使用了其中一种方法。接下来我给大家说三种方法:

(1)作用域限定符(“  :: ”)

这个相信大家并不陌生了,因为上面我们已经用到了 。
用法就是在你要使用的变量或者函数名前加上“名字空间名 ::”,如“Class1::”

(2)名字空间指令

其实这个我们之前也看到过,在最上面那段最简单的c++代码中的第二行:using namespace std;
具体用法是这样:using namespace + 空间名;
写段代码看看怎么用:
#include <iostream>using namespace std;namespace Class1{char xq[] = "我是一班的小强";void show(){    cout<<xq<<endl;}}namespace Class2{char xq[] = "我是二班的小强";void show(){    cout<<xq<<endl;}}int main(){using namespace Class1;show();Class2::show();return 0;}
运行结果还是一样的,main函数的第二行调用的show()函数为什么是名字空间Class1里面的show呢?
因为我们使用了指令了using,把Class1这个名字空间解放出来了。也就是说从main函数一行之后凡是调用Class1名字空间里面的东西都可以省略前面的;;作用域限定符。
这也就是为什么使用了using namespace std 之后,cout和endl之前可以不用加上std::啦。
那又人或说了,既然这么方便那我以后就直接这么用吧。可是还有一点需要注意的地方。
如果main函数里面我这样写:
using namespace Class1;using namespace Class2;show();
结果肯定就是编译器(我用的codeblocks)报错了。

编译器提示说show()是有歧义的。
所以使用using的时候,会把你划分的逻辑单元的围墙推倒(比喻一下),名字冲突的问题再一次产生,也就失去了我们使用名字空间的意义。
所以个人建议这种方法最好不用。

(3)名字空间声明

这种方法其实只是比第二种方法稍微改进一步。
具体看程序(前面因为一样的就省略):
int main(){using namespace Class1;using Class2::show;show();return 0;}
最后使用的是Class2里面的show。
虽然一开始你告诉编译器我使用的是Class1的名字空间,但是我任性的要使用Class2里面的show,编译器只好听你的。
这种方法容易让人产生误导,最好还是怪怪使用方法一比较靠谱些(除非你很懒)。

6.关于名字空间还需要注意的地方:

(1)无名名字空间

顾名思义,就没有名字的名字空间(我是无名氏,阿啦啦啦~~~~)
什么意思呢?请看程序
#include <iostream>using namespace std;char my[] = "我是谁?";int main(){cout<<::my<<endl;return 0;}
my是一个我们经常使用的全局变量,可能在我们没说名字空间之前你没有注意它的名字空间是什么吧?
一句话,没有定义在任何名字空间的,都属于无名名字空间。
无名名字空间这么定义:namespace {..}
无名名字空间这样使用: ::变量名(或函数名)
发明c++的人还真是无聊偷笑

(2)名字空间的嵌套

我们知道,循环、函数有嵌套,那么名字空间也是有嵌套的。
怎么个嵌套法?还是以程序说明(眼见为实)
#include <iostream>using namespace std;namespace hnsd{    namespace sjy{        namespace jsj{            char xq[] = "小强";        }    }}int main(){cout<<hnsd::sjy::jsj::xq<<endl;   // 嵌套的名字空间需要一层一层的解析return 0;}
大部分用法和上面的一样,唯一要注意的地方就是,你嵌套了多少层,就需要解析多少层(也就是::符号要用几个啦,注意上下层次的关系不要弄错了)

(3)给名字空间取别名

从上面的代码我们可以看见,如果要用xq,前面还得加上“hnsd::sjy::jsj”一长串的名字空间,如果每次调用都写这么多,是不是太麻烦了一点?
怎么办?看来只好取个别名呢?怎么取呢?看如下代码:
namespace name = hnsd::sjy::jsj;cout<<name::xq<<endl;
这效果是一样一样的。很简单吧?


2 0
原创粉丝点击