`
wsql
  • 浏览: 11883019 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

C++命名空间的解释

 
阅读更多

C++命名空间的解释

来源:代码栈的日志

使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突。在C++中,变量、函数和类都是大量存在的。如果没有命名空间,这些变量、函数、类的名称将都存在于全局命名空间中,会导致很多冲突。比如,如果我们在自己的程序中定义了一个函数toupper(),这将重写标准库中的toupper()函数,这是因为这两个函数都是位于全局命名空间中的。命名冲突还会发生在一个程序中使用两个或者更多的第三方库的情况中。此时,很有可能,其中一个库中的名称和另外一个库中的名称是相同的,这样就冲突了。这种情况会经常发生在类的名称上。比如,我们在自己的程序中定义了一个Stack类,而我们程序中使用的某个库中也可能定义了一个同名的类,此时名称就冲突了。

Namespace关键字的出现就是针对这种问题的。由于这种机制对于声明于其中的名称都进行了本地化,就使得相同的名称可以在不同的上下文中使用,而不会引起名称的冲突。或许命名空间最大的受益者就是C++中的标准库了。在命名空间出现之前,整个C++库都是定义在全局命名空间中的(这当然也是唯一的命名空间)。引入命名空间后,C++库就被定义到自己的名称空间中了,称之为std。这样就减少了名称冲突的可能性。我们也可以在自己的程序中创建自己的命名空间,这样可以对我们认为可能导致冲突的名称进行本地化。这点在我们创建类或者是函数库的时候是特别重要的。

命名空间基础

namespace关键字使得我们可以通过创建作用范围来对全局命名空间进行分隔。本质上来讲,一个命名空间就定义了一个范围。定义命名空间的基本形式如下:

namespace名称{//声明}

在命名空间中定义的任何东西都局限于该命名空间内。

下面就是一个命名空间的例子,其中对一个实现简单递减计数器的类进行了本地化。在该命名空间中定义了计数器类用来实现计数;其中的upperboundlowerbound用来表示计数器的上界和下界。

//演示命名空间

 

namespace CounterNameSpace

{
    int upperbound;
    int lowerbound; 

    class counter
    {
        int count;

    public:

        counter(int n)
        {
            if ( n <= upperbound )

            {

                count = n;

            }

            else

            {

                count = upperbound;

            }

        }

 

        void reset(int n)

        {

            if ( n < upperbound )

            {

                count = n;

            }

        }

 

        int run()

        {

            if ( count > lowerbound)

            {

                return count--;

            }

            else

{

                return lowerbound;

}

        }

    };

}


其中的upperboundlowerbound和类counter都是有命名空间CounterNameSpace定义范围的组成部分。

在命名空间中声明的标识符是可以被直接引用的,不需要任何的命名空间的修饰符。例如,在CounterNameSapce命名空间中,run()函数中就可以直接在语句中引用lowerbound

if ( count > lowerbound)

    {

        return count--;

    }


然而,既然命名空间定义了一个范围,那么我们在命名空间之外就需要使用范围解析运算符来引用命名空间中的对象。例如,在命名空间CounterNameSpace定义的范围之外给upperbound赋值为10,就必须这样写:

CounterNameSpace::upperbound = 10;

或者在CounterNameSpace定义的范围之外想要声明一个counter类的对象就必须这样写:

CounterNameSpace::counter obj;

一般来讲,在命名空间之外想要访问命名空间内部的成员需要在成员前面加上命名空间和范围解析运算符。

下面的程序演示了如何使用CounterNameSpace这个命名空间:

//演示命名空间

#include <iostream>

using namespace  std;

namespace CounterNameSpace

{

    int upperbound;

    int lowerbound;

 

    class counter

    {

        int count;

    public:

        counter(int n)

        {

            if ( n <= upperbound )

            {

                count = n;

            }

            else

            {

                count = upperbound;

            }

        }

 

        void reset(int n)

        {

            if ( n < upperbound )

            {

                count = n;

            }

        }

 

        int run()

        {

            if ( count > lowerbound)

            {

                return count--;

            }

            else

                return lowerbound;

        }

    };

}

 

int main()

{

    CounterNameSpace::upperbound = 100;

    CounterNameSpace::lowerbound = 0;

 

    CounterNameSpace::counter ob1(10);

 

    int i;

    do

    {

        i = ob1.run();

        cout << i << " ";

 

    } while (i > CounterNameSpace::lowerbound);

    cout << endl;

 

    CounterNameSpace::counter ob2(20);

    do

    {

        i = ob2.run();

        cout << i << " ";

 

    } while (i > CounterNameSpace::lowerbound);

    cout << endl;

 

    ob2.reset(100);

    do

    {

        i = ob2.run();

        cout << i << " ";

 

    } while (i > CounterNameSpace::lowerbound);

    cout << endl;

 

    return 0;

}


请注意:counter类以及upperboundlowerbound的引用都是在前面加上了CounterNameSpace修饰符。但是,一旦声明了counter类型的对象,就没有必须在对该对象的任何成员使用这种修饰符了。因此ob1.run()是可以被直接调用的。其中的命名空间是可以被解析的。

相同的空间名称是可以被多次声明的,这种声明向相互补充的。这就使得命名空间可以被分割到几个文件中甚至是同一个文件的不同地方中。例如:

namespace NS

{

int i;

}

 

//...

 

namespace NS

{

    int j;

}


其中命名空间NS被分割成两部分,但是两部分的内容却是位于同一命名空间中的。也就是NS。最后一点:命名空间是可以嵌套的。也就是说可以在一个命名空间内部声明另外的命名空间。

using关键字

如果在程序中需要多次引用某个命名空间的成员,那么按照之前的说法,我们每次都要使用范围解析符来指定该命名空间,这是一件很麻烦的事情。为了解决这个问题,人们引入了using关键字。using语句通常有两种使用方式:

using namespace命名空间名称;

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

第一种形式中的命名空间名称就是我们要访问的命名空间。该命名空间中的所有成员都会被引入到当前范围中。也就是说,他们都变成当前命名空间的一部分了,使用的时候不再需要使用范围限定符了。第二种形式只是让指定的命名空间中的指定成员在当前范围中变为可见。我们用前面的CounterNameSpace来举例,下面的using语句和赋值语句都是有效的:

using CounterNameSpace::lowerbound; //只有lowerbound当前是可见的

lowerbound = 10; //这样写是合法的,因为lowerbound成员当前是可见的

using CounterNameSpace; //所有CounterNameSpace空间的成员当前都是可见的

upperbound = 100; //这样写是合法的,因为所有的CounterNameSpace成员目前都是可见的

下面是我们对之前的程序进行修改的结果:

//使用using

#include <iostream>

 

using namespace std;

 

namespace CounterNameSpace

{

    int upperbound;

    int lowerbound;

    class counter

    {

        int count;

    public:

        counter(int  n)

        {

            if ( n < upperbound)

            {

                count = n;

            }

            else

            {

                count = upperbound;

            }

        }

 

        void reset( int n )

        {

            if ( n <= upperbound )

            {

                count = n;

            }

        }

 

        int run()

        {

            if ( count > lowerbound )

            {

                return count--;

            }

            else

            {

                return lowerbound;

            }

        }

    };  

}

 

 

int main()

{

    //这里只是用CounterNameSpace中的upperbound

    using CounterNameSpace::upperbound;

 

    //此时对upperbound的访问就不需要使用范围限定符了

    upperbound = 100;

    //但是使用lowerbound的时候,还是需要使用范围限定符的

    CounterNameSpace::lowerbound = 0;

    CounterNameSpace::counter ob1(10);

    int i;

 

    do

    {

        i = ob1.run();

        cout << i  << " ";

    }while( i > CounterNameSpace::lowerbound);

    cout << endl;

 

    //下面我们将使用整个CounterNameSpace的命名空间

    using namespace CounterNameSpace;

    counter ob2(20);

    do

    {

        i = ob2.run();

        cout << i  << " ";

    }while( i > CounterNameSpace::lowerbound);

    cout << endl;

 

    ob2.reset(100);

    lowerbound = 90;

    do

    {

        i = ob2.run();

        cout << i << " ";

    }while( i > lowerbound);

 

    return 0;

}


上面的程序还为我们演示了重要的一点:当我们用using引入一个命名空间的时候,如果之前有引用过别的命名空间(或者同一个命名空间),则不会覆盖掉对之前的引入,而是对之前引入内容的补充。也就是说,到最后,上述程序中的stdCounterNameSpace这两个命名空间都变成全局空间了。

没有名称的命名空间

有一种特殊的命名空间,叫做未命名的命名空间。这种没有名称的命名空间使得我们可以创建在一个文件范围里可用的命名空间。其一般形式如下:

namespace

{

    //声明

}


我们可以使用这种没有名称的命名空间创建只有在声明他的文件中才可见的标识符。也即是说,只有在声明这个命名空间的文件中,它的成员才是可见的,它的成员才是可以被直接使用的,不需要命名空间名称来修饰。对于其他文件,该命名空间是不可见的。我们在前面曾经提到过,把全局名称的作用域限制在声明他的文件的一种方式就是把它声明为静态的。尽管C++是支持静态全局声明的,但是更好的方式就是使用这里的未命名的命名空间。

std命名空间

标准C++把自己的整个库定义在std命名空间中。这就是本书的大部分程序都有下面代码的原因:

using namespace std;

这样写是为了把std命名空间的成员都引入到当前的命名空间中,以便我们可以直接使用其中的函数和类,而不用每次都写上std::

当然,我们是可以显示地在每次使用其中成员的时候都指定std::,只要我们喜欢。例如,我们可以显示地采用如下语句指定cout

std::cout << “显示使用std::来指定cout”;

如果我们的程序中只是少量地使用了std命名空间中的成员,或者是引入std命名空间可能导致命名空间的冲突的话,我们就没有必要使用using namespace std;了。然而,如果在程序中我们要多次使用std命名空间的成员,则采用using namespace std;的方式把std命名空间的成员都引入到当前命名空间中会显得方便很多,而不用每次都单独在使用的时候显示指定。


分享到:
评论

相关推荐

    C++命名空间小结

    C++命名空间理解及小结,命名空间的使用方法。

    c++ 命名空间

    C++ using namespace std 详解  所谓namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。

    C++命名空间 C++ Builder代码演示

    C++命名空间 C++ Builder代码演示

    C++命名空间.docx

    标题提到的"C++命名空间"主要涉及到以下知识点: 1. **命名空间的作用**:命名空间的主要目的是解决标识符的可见性和重名问题。通过将相关的函数、类和变量分组到一个命名空间内,可以确保每个标识符在其自身的命名...

    1.C++中的命名空间0524.pptx

    C++的命名空间是什么?刚开始学习C++,一文清晰明了的分清楚命名空间的概念。后续持续更新自己的C++笔记

    C++命名空间和概念资料

    C++的命名空间(namespace)是为了解决标识符命名冲突的问题而引入的关键字,它允许程序员在不同的命名空间中定义相同名称的标识符,而不会互相干扰。在C++标准程序库中,所有的标识符都被定义在一个名为`std`的命名...

    C++命名空间.pdf

    在C++编程语言中,命名空间(namespace)是一个重要的概念,它主要用于组织代码,避免标识符之间的命名冲突。C++标准库中的所有函数、类和其他标识符都被定义在一个名为`std`的命名空间内。这使得我们可以明确地知道...

    标准C++引入命名空间

    标准C++引入命名空间。基本知识。有需要的可以下载。

    protobuf中的命名空间使用demo(C++)

    protobuf 命名空间,包

    实例讲解C++ 命名空间

    C++ 命名空间实例讲解 C++ 命名空间是 C++ 编程语言中的一种机制,用于解决函数、类、变量等命名冲突的问题。它可以作为附加信息来区分不同库中相同名称的函数、类、变量等。 定义命名空间的语法使用关键字 ...

    C++ std命名空间.pdf

    在C++编程语言中,命名空间(namespace)是一个重要的概念,它的主要目的是解决标识符命名冲突的问题,尤其是在大型项目中,不同模块可能使用相同的名字。通过将相关的标识符组织在特定的命名空间内,可以避免全局...

    C++命名空间自定义及使用(附完整程序)

    C++命名空间自定义及使用(附完整程序)

    C++-命名空间namespace

    using namespace是使用命名空间 C++

    编程:C++命名空间的使用 学习心得

    c++语言提供一个全局的命名空间namespace,可以避免导致全局命名冲突问题。举一个实例,请注意以下两个头文件:

    异常处理和命名空间(2013级-C++程序设计)

    2013级,C++程序设计课件。第14章 异常处理和命名空间,内容 14.1 异常处理 14.2 命名空间 14.3 使用早期的函数库

    C++ std命名空间 (2).docx

    【C++命名空间详解】 命名空间(namespace)是C++编程语言中的一种机制,用于组织代码,避免在大型项目中由于标识符重名而引发的冲突。命名空间通过定义一个独立的作用域,使得在同一程序中可以有多个同名标识符而...

    C++ std命名空间 (2).pdf

    在C++编程语言中,命名空间(namespace)是一种组织代码的重要机制,它的主要目标是解决标识符命名冲突的问题。在大型项目中,由于不同模块可能会使用相同的名字来定义变量、函数或类,如果没有适当的隔离,就可能...

    c++制作自己的namespace命名空间

    visual c++ namespace命名空间 用法

    C++命名空间5种常见用法实例解析

    C++命名空间5种常见用法实例解析 C++命名空间是一种避免名称冲突的方法,它提供了一种新的作用域,通常用于避免命名冲突。在C++中,命名空间的使用可以带来很多好处,例如模块化应用程序、匿名命名空间、解决枚举...

    C++名字空间/C++命名空间

     名字空间是C++提供的一种解决符号名字冲突的方法。  一个命令空间是一个作用域,在不同名字空间中命名相同的符号代表不同的实体。  通常,利用定义名字空间的办法,可以使模块划分更加方便,减少模块间的相互...

Global site tag (gtag.js) - Google Analytics