C++命名空间

Posted 月疯

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++命名空间相关的知识,希望对你有一定的参考价值。

大型应用程序经常使用来自不同厂商的开发库,几乎不可避免会使用相同的名字,也就是说一个库中定义的名字可能与其他库中的名字相同而产生冲突,使得程序员不能组合格子独立的开发库到一个程序中。

命名空间是用来限定名字的解析和使用范围的,他是C++开发大型程序的工具之一

命名空间的原理是将全局作用于划分为一个一个的命名空间,每个命名空间是一个独立的作用域,在不同命名空间内部定义的名字彼此互不影响,从而有效的避免了命名空间的污染。

命名空间的定义形式:

namespace 命名空间名{
         ......
}

命名空间可以再全局作用于或其他命名空间内部定义,单不能再函数、结构体或类内部定义,且要保证命名空间之间不会出现名字冲突。

在命名空间作用域内,可以包含以下内容:

1、变量、对象以及他们的初始化

2、枚举常量

3、函数声明以及函数定义

4、类、结构体声明与实现

5、模板

6、其他命名空间

每个命名空间是一个作用域

定义再命名空间中的实体称为命名空间成员。命名空间中每个名字必须是该空间中的唯一实体,不同命名空间可以具有同名成员。

namespace A{    //定义命名空间A
    int fun,j;
    int fun(){return 10;}  //错误,通一命名空间不能有相同的名字
}
namespace B{    //定义命名空间B
    int fun,j;  //正确,不同命名空间可以有相同的名字
}

在命名空间中定义的名字可以被命名空间中的其他成员直接访问,命名空间外部的代码必须指出名字定义再那个命名空间中,即作用域运算限定命名空间,形式为:

命名空间::成员名

例如:

namespace A{

    int i=10;
    void output1(){count<<i;}//同一个命名空间直接引用成员i
}
void output2(){count<<A::i;} //引用命名空间限定成员A::i

命名空间可以是不连续的

命名空间可以再几个部分中分开定义,即命名空间是累积的。一个命名空间可以分散在多个文件中。

namespace A{

     int i;

}

namespace B{

     int i,j;

}

namespace  A{

     int j;

}

接口和实现分离

命名空间可以不连续意味着可以做以下事情:

1、命名空间成员如果是类,可以将作为类接口的函数声明和对象声明放在头文件中,使用这些命名空间成员的文件可以包含这些头文件。

2、命名空间类成员的定义可以放在单独的源文件中。

定义命名空间成员

在命名空间内部定义的函数可以使用同一命名空间中定义的名字。

namespace A{
     complex sub (complex& c1,complex& c2);
}

也可以在命名空间外部定义命名空间成员:

A::complex A::sub(somplex& c1,complex& c2);
{complex c;

 c.setdata(c1.getr()+c2.getr(),c1.geti()+c2.geti());

 return c;
}

全局命名空间

定义在全局作用域的名字(任何类、函数或命名空间外部声明的名字)是定义在全局命名空间中的。全局命名空间存在于每个程序中,是隐式的。

可以用作用域运算符引用全局命名空间的成员:

int i=10;    //全局作用域
namespace A{  //使用命名空间
void output(){cout<<::i;}  //使用全局作用域
}

嵌套命名空间

嵌套命名空间中的名字遵循名字规则:外围命名空间中的声明的名字被嵌套命名空间中同一名字的声明所屏蔽。

namespace outer{
    int i;
    namespace inner{
        void f(){i++;}
        int i;
        void g(){i++;}
        void h(){outer::i++;}
    }

}

未命名的命名空间

定义命名空间时如果没有给出命名空间名字,称为未命名的命名空间,定义形式为:

namespace{
    ......
}
  1. 未命名空间的中定义的名字可以直接使用,没有命名空间名字来限定他们
  2. 未命名空间可以再给定文件中不连续,但不能跨越文件,每个文件有自己的未命名的空间。本质上在一个文件中所有未命名空间会被系统用同一个表示代替,且区别于其他文件标识。

未命名空间的命名空间专门用于声明局部于文件的实体。

未命名的命名空间中定义的名字只在包含该命名空间的文件中可见。如果另一文件包含一个未命名的命名空间,俩个命名空间不相关,可以定义相同名字的实体。

命名空间成员的使用:

引用命名空间成员的形式为:

命名空间::成员名

例如:

nspath::=10;
nspath::nsdir::i=10;//嵌套命名空间的使用

命名空间的别名

可以为命名空间起一个别名来代替较长的命名空间名,形式为:

namespace 命名空间别名 = 命名空间名;

namespace ns_with_very_long_name{......}
namespace NWVLN=ns_with_very_long_name;
namespace NSPD=nspath::nsdor;

1、using声明

可以使用using声明引入命名空间成员,形式为:

using 命名空间名:: 命名空间成员名;

一个using声明一次引入一个命名空间成员,它使得无论程序使用那些名字,都非常明确。例如:

using std ::count;//引入标准命名空间std的cout

2、using指示

using指示的形式为:

using namespace 命名空间名;

using指示使得特定命名空间的所有名字可见,没有限制。

namespace A{
     int i,j;
}
void f()  //函数f再全局作用域的定义
{   using namespace A;  //插入命名空间A的作用域
    cout<<i*j<<endl;  //直接使用命名空间A中i和j
    
}

类和命名空间

对命名空间内部使用的名字的查找遵循常规的C++规则:

namespace A{
    int i;
    namespace B{
        int i,j;
        int fi(){
            int j;
            return i;
    }
    }
    int f2(){return j;}  //错误,j未被定义
    int j=i;


}

在类作用域查找名字的时候,首先在成员本身中查找,然后在类中查找,然后检查外围作用域。当类包含在命名空间中的时候,发生相同的查找;首先在成员中查找,然后在类中找,再在外围命名空间中找;

(1)实参相关的查找与类类型形参

有简单程序:

std::string s;

getline(std::cin,s);调用 std::getline

接受类类型形参的函数,以及与类本身定义在同一命名空间的函数,在用类类型对象作为实参的时候是可见的。

当编译器再变异getline(std::cin,s);的时候,他在当前的作用域以及定义cin和string的类型的命名空间中查找匹配的函数,进而再std命名空间找到有string类型定义getline函数,所以条用getline函数不用std::限定。

(2)标准命名空间的使用

标准库的所有名字都是在一个名为std的标准命名空间中定义的,我们之前几乎所有的实例代码使用的都是std 的using指示:

using namespace std;//加入标准库命名空间std到程序作用域中

这样做程序可以不必对每个std成员(如cin,cout,endl)--处理。但是也导致程序和其他库出现冲突的机会多了起来。

使用std限定的一个好处就是对每个std成员做限定,例如:

std::cout<<"hello,world"<<std::endl;

这样做虽然不方便,但是最大程度的避免了与标准命名空间名字的冲突。

也可以用如下方法:

using std :: cin;
using std :: cout;
using std::endl;

 

 

 

 

 

以上是关于C++命名空间的主要内容,如果未能解决你的问题,请参考以下文章

在标头和源代码 (cpp) 中创建 C++ 命名空间

VSCODE 片段 PHP 自动填充命名空间

XCode、命名空间、C++ 和代码可移植性

未命名的命名空间和 Visual C++ 链接器性能

2)C++命名空间的定义

C++快速入门(命名空间,输入输出,缺省函数,函数重载)