首页 > 代码库 > C++之命名空间

C++之命名空间

C中是没有命名空间这个概念的,是C++中新引入的一个东西,为了处理同名的冲突。

其实命名空间就是封装的一个概念。把一些变量、函数、类给封装起来。和类的封装概念很像,但是比类的封装要大。

 

一、浅析

1. 自定义定义命名空间

格式:Namespacename{}

namespace my{
       int i=2;
       void foo()
       {cout<<"my:"<<i<<endl;}
}
namespaceyour{
       class A{};
}


2. 使用命名空间中的东西(3种方法)

namespace my{
       int i=2;
       void foo()
       {cout<<"my:"<<i<<endl;}
}

(1)using namespace my; 之后的程序就可以使用my中的所有东西(i和foo())

using namespace my;
int _tmain(int argc, _TCHAR* argv[])
{
       foo();//OK
       cout<<i<<endl;//OK
       system("pause");
       return 0;
}

(2)using my::foo,之后的程序就可以使用my中foo了。

using my::foo;
int _tmain(int argc, _TCHAR* argv[])
{
       foo();//OK
       cout<<i<<endl;//ERROR
       system("pause");
       return 0;
}

(3)程序中直接使用my::i和my::foo()

int _tmain(int argc, _TCHAR* argv[])
{
       my::foo();//OK
       cout<<my::i<<endl;//OK
       system("pause");
       return 0;
}


思考:其实命名空间和类的封装很像。一个命名空间里想要使用另一个命名空间里的东西,必须using或命名空间::。

 

二、深析

1. 定义命名空间

命名空间是跨文件的。也就是说可以在多个cpp文件中定义同一命名空间,这样的作用就是可以往已存在的命名空间中加入东西。

namespacestd{

       int i=2;

}

此代码的目的就是想往命名空间std加入变量i。(虽然很不提倡,但无语法错误)

 

其实C++标准库也是这么做的。因为标准库中一个命名空间包含的函数或类是很多的,不可能把这些函数、类都写在一个cpp文件中。所以利用不断往一个命名空间加入东西来形成完整的标准库的命名空间。

 

2. 使用命名空间

前面提到的使用命名空间中东西,的前提是该命名空间的定义已经在本cpp中,如果不存在,需要#include把要使用的命名空间的定义include进来。例如:inlcude<iostream>usingnamespace std;

看到这里引出另一个问题:

C中的#include<xxx.h>和C++中的#include<xxx> using namespace xxx的区别?

其实这2个语句都是想要使用xxx中的东西。C中没有命名空间这个概念,所以不需要namespace。而C++中,标准库的函数都是放在某一命名空间中的,所以必须要有using namespace xxx;

也就是说iostream中的各种函数都是在std中的,显然std还包括其他很多东西。

 

思考:为何C++要把include<xxx.h>中的.h给去掉?

因为我们在写C++程序时,有时会把类的定义写在.h文件中,而把类的实现放在cpp文件中。

//t.h
class A
{
public:void foo();
};

//t.cpp
#include "stdafx.h"
#include<iostream>
using namespace std;
#include "t.h"
void A::foo(){
       cout<<"print"<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
       A a;
       a.foo();
       system("pause");
       return 0;
}


这里在t.cpp中,我们#include”t.h”,我们只是想要类A的定义式。

而上面我们讲到,C++中的#include<xxx>我们是想要使用xxx里面的东西。显然xxx中肯定不只是定义式,而且必须是已经实现了的。

 

所以这里C++这个改动目的就是为了区别xxx和xxx.h。xxx里是已经定义且实现好了的东西。而xxx.h可以是只是定义式。

所以我们只要见到xxx,就能确定它是定义实现了的。而见到xxx.h,它可能只是定义式。

 

3. include的本质含义

很简单,就是把include后面的文件放到本文件中进行编译执行。

 

4. global namespace

C++中任何一段代码都在某个命名空间。所有没有定义命名空间的,C++默认是都属于global namespace。注意global namespace和其他的命名空间本质上是没有区别的。

namespace my{
int i=1;
}
int i=2;
using namespace my;
int _tmain(int argc, _TCHAR* argv[])
{
       i=3;//ERROR
       system("pause");
       return 0;
}

由于i=2是没有定义命名空间,属于global namespace。而using namespace my,所以下面的main是在global namspace中的,所以可以使用globalnamespace,也可以使用my namespace。而由于两个命名空间都有i,所以系统不知道该调用哪个,就会出错。

 

5. 无名命名空间

namespace {

int i=1;

}

显然无法被别的文件使用。它只是在本文件中可以被有效使用。注意和globalnamespace的区别。

 

6. 不要给C++中的标准库加入任何东西

例如上面的1提到的:

namespacestd{

       int i=2;

}

如果这段代码被别的程序引用,虽然这段代码不会出现编译、运行错误。但是在C++中有可能会出现不明确的行为,有时会出现莫名其妙的东西。所以一定不要加。

 

7. 嵌套命名空间

namespacensl
   { const int RATE=0.08; //常量
   double pay;       //变量
   double tax()       //函数
      {return 1.2*RATE;}
   namespace ns2       //嵌套的命名空间
      {int age;}
   } 
如果想输出命名空间nsl中成员的数据,可以采用下面的方法:

cout<<nsl::RATE<<endl;
cout<<nsl::pay<<endl;
cout<<nsl::tax()<<endl;
cout<<nsl::ns2::age<<endl; //需要指定外层的和内层的命名中间名

 

C++之命名空间