使用namespace(命名空间)的正确方法

118 篇文章 8 订阅

使用namespace(命名空间)的正确方法

【C++入门】命名空间的定义和使用

--------------------------------------------------------

同名变量的访问优先级:局部域 > 全局域 > 命名空间域

================================

使用namespace(命名空间)的正确方法

使用namespace(命名空间)的正确方法

el/2022/9/22 8:18:13

命名空间(namespace)在C++中的作用非同一般。本文目的不在于阐述命名空间的语法,而在于演示命名空间的使用方法,或者说是使用命名空间的小窍门。

命名空间可以简单的将一些命名(name)用另一个命名打包封装起来。比方说:

namespace net {
  class Socket {
    ...
  };
}
...
net::Socket socket;

经过这样的封装以后,如果在两个库(library)都实现了Socket类,只要它们命名空间的名字不同,你就可以同时使用它们而没有任何命名上的冲突。

但这样做还是有问题:假如两个公司都要写一个network库,那么当她们编写代码的时候都使用Socket命名他们的类的可能性有多大?我猜是接近100%。

命名空间的名字最好是方便输入的,就是说命名空间的名字最好别太长了,2-4个字符就可以了。抱着这样的想法,那两个公司把他们的命名空间叫做net的机会又是多大呢?5%还是10%?

不难看出,命名空间并没有解决所有问题,它只是使发生命名冲突的机会相对小了而已。

有一种叫做“工业化长度”的方法(Industrial Strength Solution),这种方法在命名namespace的时候使用长的唯一的名称,而在程序里使用短的别名。如此network库就可能会是这个样子:

namespace net_33843894 {
  class Socket {
    ...
  };
}

net_后面的数字是由一个随机数产生器产生的。为了以后描述方便,这里我们假定上面的代码是放在<netlib>头文件里。

用户使用我们的库的时候,就要编写他自己的头文件<mynetlib>,包含下面的内容:

#include <netlib>
namespace net = net_33843894;

他创建了一个在本工程内有效的别名,用来代表提供给他的库中的命名空间。如果名称net已经被别的库使用了,那么他还可以另选一个名字代替,例如:net2,sock,或者别的什么。

这样就万事大吉了么?还没有。你还要做一件事:使你的库用起来更简单、更方便。在这个讲究完美的社会里,人们双击一个安装文件后,你的库在他们的开发环境里就应该是可用的,接下来就是#include <netlib>,再接下来他们就可以去忙别的了。

然而,现在的情况是,用户为了使用你的库需要创建一个他自己的头文件,虽然这并没有什么大不了的,但不是每个用户都能忍受这一点。解决的方法就是直接提供一个合理的缺省值,如果用户觉得不合适也可以取消,所以,在你的头文件里使用预编译选项,如下:

namespace net_33843894 {
  class Socket {
    ...
  };
}
#ifndef NO_NET_33843894_ALIAS
  namespace net = net_33843894;
#endif

这样我们就给命名空间的名字提供了一个缺省值,如果这个名字已经有人用了,那么用户可以定义一个NO_NET_33843894_ALIAS宏,别名就会被取消。

不幸的是,即使是使用了短的别名net,当你使用Socket类的方法不对的时候,在我所用过的编译器中,没有一个能够在错误提示信息里显示的短的别名,而是仍然使用net_33843894::Socket。读起来有些费劲。

怎么办?看我的。

#ifdef NO_NET_33843894_ALIAS
namespace net_33843894 {
#else
namespace net {
#endif
  class Socket {
    ...
  };
}
#ifndef NO_NET_33843894_ALIAS
  namespace net_33843894 = net;
#endif

如果没有定义宏NO_NET_33843894_ALIAS, 就直接给命名空间起个短一点的名字,把别名弄长点就可以了。这样,错误信息读起来就会顺眼多了。

【C++入门】命名空间的定义和使用

文章目录

  • 一、命名空间是什么
  • 二、命名空间的定义
  • 三、命名空间的使用

一、命名空间是什么

在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染。

命名空间:用于解决命名冲突
一个命名空间就是一个新的作用域,其中的所有内容都局限于该空间中。
同名变量的访问优先级:局部域 > 全局域 > 命名空间域

二、命名空间的定义

定义命名空间,需要使用到namespace关键字。
做法:在namespace后面跟命名空间的名字,然后接一对{}即可。
{}中的就是命名空间的成员。
注:命名空间的定义是可嵌套的。

// lx是命名空间的名字,一般开发中是用项目名字做命名空间名
namespace lx
{// 命名空间中可以定义变量/函数/类int a;
}

一个工程中允许存在多个同名的命名空间,这些同名的命名空间最后会被编译器合成到同一个命名空间中。

std 是C++标准库的命名空间名,C++将标准库的定义实现都放在这个命名空间中。

三、命名空间的使用

谈到命名空间的使用,就得介绍一个域操作符::
例如,::a 的意思就是访问全局变量a
例如,lx::a的意思就是访问命名空间lx里的变量a

命名空间的使用有三种方式:

1.命名空间名称+域操作符

int main()
{printf("%d\n", lx::a);return 0;  
}

2.使用using将命名空间中某个成员引入

using lx::a;
int main()
{printf("%d\n", a);return 0;  
}

3.使用using namespace将命名空间引入

using namespce lx;
int main()
{printf("%d\n", a);return 0;  
}

std 命名空间的使用惯例:

  1. 日常练习中建议直接using namespace std
  2. using namespace std展开,标准库就全部暴露出来了,如果我们定义的变量 / 函数 / 类跟标准库里的重名,就会产生冲突
  3. 所以在项目开发中建议:
  • 指定访问,例如:

std::cout << "hello world!" << std::endl;
  • 展开常用的,例如:

using std::cout;
using std::endl;
cout << "hello world!" << endl;

ps:关于coutcin更多复杂的用法,比如控制浮点数输出精度、控制整型输出进制格式,由于C++兼容C语言,这些又用得不是很多,我们就不展开学习了。后续如果有需要,我们再配合文档学习。

C++库研究笔记——命名空间namespace 嵌套后的作用域问题

总结:

1. ::ant 表根命名空间,或匿名空间

2. 同时存在 ::ant::i 和::ant::blas::i,  ant::detail::i 时,

      在::ant::detail中使用 i 时,默认调用ant::detail::i

3. 平级namespace 调用用,要加相应的命名空间

4. 域内命名空间可省

5. 即使存在多个相同名字的命名空间,不会报错,按最局部分调用原则调用,如同全局变量与局部变量名字一样时,优先调用局部变量


代码:

    #include <stdlib.h>
     
    #include <iostream>
     
    namespace detail
    {
    const int i=99;
    }
     
    namespace ant
    {
    namespace blas
    {
    const int i=0;
    }//end blas
     
    const int i=3;
     
    namespace detail
    {
    const int i=33;
    void test()
    {
        std::cout<<"i:"<<i<<std::endl;  // 33
        std::cout<<"::detail::i"<<::detail::i<<std::endl; // 99
        std::cout<<"detail::i"<<detail::i<<std::endl; // 33
        std::cout<<"::ant::blas::i:"<<::ant::blas::i<<std::endl;// 0
        std::cout<<"ant::blas::i"<<::ant::blas::i<<std::endl;   // 0
        std::cout<<"blas::i"<<blas::i<<std::endl;   // 0 平级
        //std::cout<<"::blas::i"<<::blas::i<<std::endl;   // error
        std::cout<<"ant::i"<<ant::i<<std::endl;// 3
    }
    }// end detail
     
    }//end namespace ant
     
    using namespace std;
    int main()
    {
        ant::detail::test();
        return 0;
    }


————————————————
版权声明:本文为CSDN博主「GeoAnt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/mathgeophysics/article/details/9731767

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值