命名空间


文章目录

  • 命名空间
  • 前言
  • 命名空间概念引入
    • 1.1 命名空间定义
      • 1.1.1 命名空间的一般定义方式
      • 1.1.2 命名空间的嵌套定义
      • 1.1.3 不连续的命名空间
    • 1.2 命名空间使用
      • 1.2.1 第一种:利用命名空间标识符及作用域限定符引入命名空间成员
      • 1.2.2 第二种:使用using引入命名空间的成员
      • 1.2.3 第三种:使用using namespace 引入命名空间所有成员
    • 1.3 标准命名空间std
    • 1.4 扩展阅读
    • 1.5 相关问题
  • 总结
  • 参考资料

前言

编译工具:visual studio 2019

语言:C++


命名空间概念引入

   当C++工程较大时,程序内存在大量的变量、函数和类,如果这些变量、函数和类都存在于同一个作用域中,一不小心就可能会导致命名冲突。为了解决这个问题,C++引入了命名空间(namespace)这个概念,这样在不同的命名空间中允许存在同名的标识符。有了命名空间我们就可以在程序中有效地避免命名冲突,下面举一个利用命名空间解决命名冲突问题的例子。

   例程1:

#include <iostream>
namespace N1 //定义命名空间N1
{  int a = 10;
}
namespace N2 //定义命名空间N2
{  int a = 30;
}
int main()
{  int a = 50;  printf("N1::a = %d\n", N1::a); //输出命名空间N1中的成员变量a  printf("N2::a = %d\n", N2::a); //输出命名空间N2中的成员变量a  printf("a = %d\n",a);//输出主函数中的变量a  return 0;
}

输出结果:

图1 例程1运行结果

  例程1中定义了两个命名空间N1和N2,两个命名空间和主函数中都有a变量,但是并没有产生命名冲突,这就是使用namespace的好处。命名空间其实是对标识符的名称进行本地化,以避免命名冲突或名字污染。下面说一下命名空间的定义方式。


1.1 命名空间定义

   例程1中已经展示使用命名空间的场景,下面我们详细说一下定义命名空间的几种方式。

1.1.1 命名空间的一般定义方式

   例程2

namespace N3 //定义命名空间N3
{  int a;int Add(int x, int y)//成员函数  {  return x + y;  }
}

   例程2中定义的命名空间N3,称为普通命名空间,C++还有一个自带的标准命名空间std,下文会提到。可以看到,在命名空间中既可以定义变量,也可以定义函数。

1.1.2 命名空间的嵌套定义

   例程3

namespace N4
{  int a;  int b;  int Add(int x, int y)  {  return x + y;  }  namespace N5  {  int c;  int d;  int Sub(int x, int y)  {  return x - y;  }  }
}

   例程3中定义的两个命名空间N4和N5,其中N4包含N5,这说明N4的作用域比N5的大。

1.1.3 不连续的命名空间

   例程4

namespace N6
{int a;int Add(int x, int y){return x + y;}
}namespace N6
{int Mul(int left, int right){return left * right;}
}

  命名空间可以定义在几个不同的部分中,即命名空间可以由几个单独定义的部分组成1。换句话说,同一个工程中允许存在多个相同名称的命名空间,编译器最后会将同名的命名空间合为一个。例程3中,两个命名空间会被合成一个命名空间N6,N6中包括变量a、函数Add和函数Mul。

   以上讲述三种方式命名空间的定义方式,需要注意的一点是:定义一个命名空间就是定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中,在命名空间之外不能直接调用


1.2 命名空间使用

   前面我们学会了如何定义命名空间,那命名空间中成员该如何使用呢?其实命名空间有三种使用方式。

1.2.1 第一种:利用命名空间标识符及作用域限定符引入命名空间成员

   例程5

#include <iostream>
namespace N {int a = 10;
}
int main()
{int a = 30;printf("命名空间N中的变量a = %d\n", N::a); //打印命名空间N中的变量aprintf("main函数中的变量a =  %d\n", a); //打印主函数中的变量areturn 0;
}

运行结果:

图2 例程5运行结果

   例程5中,我们想使用变量a,则可以通过命名空间标识符“N”和作用域限定符“::”引入变量a,可以看到命名空间中的成员变量a和主函数中的局部变量a,输出值不同。

1.2.2 第二种:使用using引入命名空间的成员

   例程6

#include <iostream>//输入输出流头文件,注意头文件不带后缀.h
namespace N {int a = 10;int b = 20;
}using N::a;// 引入变量a
using N::b;// 引入变量b
int main()
{int a = 30;printf("命名空间N中的变量b = %d\n", b); //打印命名空间N中的变量bprintf("main函数中的变量a =  %d\n", a); //打印主函数中的变量aprintf("命名空间N中的变量a = %d\n", N::a); //打印命名空间N中的变量areturn 0;
}

运行结果

图3 例程6运行结果

   例程6中,通过using引入b,使用命名空间中成员变量时,不用再添加命名空间标识符“N”和作用域限定符“::”,这样在写程序时会方便不少。另外可以注意到,主函数中的局部变量会屏蔽命名空间中的同名变量(比如a),虽然我们使用using引入a,但如果想使用命名空间中的a,还是需要利用命名空间标识符“N”和作用域限定符“::”。

1.2.3 第三种:使用using namespace 引入命名空间所有成员

   例程7

#include <iostream>
namespace N {int a = 10;int b = 20;int Add(int left, int right){return left + right;}
}using namespace N;//使用using namespace 引入命名空间成员
int main()
{printf("a = %d\n", a);printf("b = %d\n", b);int c = Add(a, b);printf("a+b = %d\n", c);return 0;
}

运行结果:

图4 例程7运行结果

   可以看到使用using namespace可以把命名空间N中的成员全部引入,这样就能直接使用命名空间中的成员变量了。


1.3 标准命名空间std

   在1.1节讲到命名空间的定义可以是不连续的,标准命名空间std也不例外,std的定义被分散在多个头文件里2,比如标准输入/输出头文件 <iostream> 中就定义了一个标准命名空间3,<iostream>里面的函数或类被放在std命名空间中,比如cin和cout这两个函数的名字就放在命名空间std里面,如果我们想使用cout函数,那就必须使用std命名空间引入这个函数。在上文中我们已经知道了命名空间的三种使用方式,下面就利用这三种方式使用标准命名空间std。

   第一种:命名空间标识符+作用域限定符

#include<iostream>int main()
{std::cout << "Hello world!!!\n";return 0;
}

   第二种:使用using引入某个成员(例如引入cout函数)

#include<iostream>
using std::cout;int main()
{cout << "Hello world!!!\n";return 0;
}

   第三种:使用using namespace引入所有成员

#include<iostream>
using namespace std;
int main()
{cout << "Hello world!!!\n";return 0;
}

   以上程序中,展示了使用函数cout的方法。cout存在于头文件<iostream>的标准命名空间std(局部作用域)中,故需要利用标准命名空间引入。


1.4 扩展阅读

   早期标准库将所有功能函数都在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可。比如在早期,如果我们想使用<iostream.h>中的函数,只需在程序开头加上#include<iostream.h>即可(c++标准已经明确表示不支持这种用法了,所以理论上来说这种用法是非法的,但有些老旧编译器还支持这种用法4),不用考虑命名空间(事实上,那时候还没有命名空间)。
   后来,为了使程序更加模块化,最主要的是防止命名冲突,人们创造了命名空间这个概念(1998年)。为了使用命名空间,大佬对<iostream.h>头文件进行改造,改造好的头文件起名为<iostream>,在<iostream>中,定义了标准命名空间std,然后把<iostream.h>的内容封装到了std命名空间中5。这样如果我们想使用cout,必须先添加头文件<iostream>,有了这个头文件,我们还只能访问该文件的全局作用域,要想访问该文件中std命名空间(局部作用域)的内容6,就需要利用命名空间的使用规则处理,上面的程序已经展示了三种使用标准命名空间的方法,诸君请往上看。


1.5 相关问题

看了以上内容,有的人可能要问以下几个问题:

  问题:到底是标准命名空间存在于标准库中,还是标准库的东西存在于命名空间中?
   回答:C++有很多标准库,可以分为10类7。每个标准库中都会存在一个标准命名空间std,库中的变量、函数、类存在于std中。在第一节命名空间定义中我们已经讲过,编译器最后会把相同名称的命名空间合成为一个。因此无论我们调用了几个标准库,标准命名空间最后都会合并成一个。因此以上两种说法,在不同的角度上看都对。另外细心的看官可能已经发现,在例程1中,使用printf函数时,并没有使用命名空间进行限定,但是程序可以正常运行,这说明printf函数存在于头文件<iostream>的全局作用域中,而像cin、cout等存在于<iostream>的局部作用域中8。因此有的人说标准库的一切都放在了std中应该是不对的吧?顺便说一下,在visual studio 2019编译器中,cstdio和stdio.h这两个标准输入输出头文件里面也有printf函数9

   问题:为什么不把标准库中所有的东西全部放到std当中,这样我们在使用的时候直接添加一句using namespace std;就完事了,何必又多一句#include<iostream>呢?
   回答:确实可以把标准库的东西都放在标准命名空间中,但是这又存在了一个新的问题,以前程序猿写的C++代码都依赖于旧的头文件,如果把所有东西放在std中,会导致以前的代码无法运行。所以为了兼容以前的C++代码,人们把标准命名空间分裂,各个部分的代码再重新包装,形成了新的头文件。比如把包含了<iostream.h>头文件内容的标准命名空间部分放到新版头文件<iostream>中。这样#include<iostream.h>相当于#include<iostream>和using namespace std;的组合,如此以前的程序只需要把头文件的.h后缀去掉,再加上一句using namespace std;就能在新标准下运行了。


总结

  本文介绍了命名空间的相关概念,说明了为什么要创建命名空间的原因,并举例展示了命名空间的定义和使用的三种方式。文中还提到了标准命名空间std,在扩展阅读中你可以进一步理解命名空间的意义,在相关问题中提出了两个阅读中可能会产生的问题,并给出了相关回答。

  以上就是本文的全部内容,文章通过查看网上的资料整理而成,有些部分是我经过思考得来,有可能不对,所以本文只能供大家参考,如果你全部都相信,不如没有看到这篇文章。如您发现错误,还请批评,如有疑问也可在评论中留言。


参考资料


  1. C++ 命名空间 | 菜鸟教程 (runoob.com). ↩︎

  2. 请问:名字空间std是在哪个文件里定义的?-CSDN论坛. ↩︎

  3. using namespace std中的std定义在哪个文件_loudyten的专栏-CSDN博客. ↩︎

  4. (笔记)什么是命名空间 为什么C++头文件有的要加.h有的不用加.h_*的专栏-CSDN博客. ↩︎

  5. C++std命名空间详解_rioalian的博客-CSDN博客. ↩︎

  6. 由string头文件和std命名空间说开去:为什么引入头文件的同时还需要使用namespace? - 知乎 (zhihu.com). ↩︎

  7. C++标准库和标准模板库_迂者-贺利坚的专栏-CSDN博客_c++模板库. ↩︎

  8. 为什么在C++中使用printf时不使用命名空间std不会报错 - 沃锋问答-赞臣社区旗下知识互动平台 (zanchen.net). ↩︎

  9. c++中printf函数在哪几个头文件中有?_百度知道 (baidu.com). ↩︎

命名空间的定义、使用和存在的意义相关推荐

  1. 【C++入门】命名空间的定义与使用

    目  录 1 命名空间 1.1 命名空间定义 1.2 命名空间使用 1 命名空间 在C/C++中,变量.函数和类都是大量存在的,这些变量.函数.类的名称将都存在于全局作用域中,可能会导致很多冲突. 使 ...

  2. C++无名命名空间中定义的函数不使用造成“-Wunused-function”警告问题

    C++无名命名空间使用问题 零.前言 一.问题 二.无名空间 三.gcc编译器警告和错误提示参数 四.问题解决 五.完整代码演示 零.前言 C++ 语言就是博大精深,各种语法问题,都值得深入探究一下, ...

  3. 命名空间的定义和使用

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

  4. 命名空间的定义及使用

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

  5. 定义serialVersionUID的作用与意义整理

    实现java.io.Serializable这个接口是为序列化,serialVersionUID 用来表明实现序列化类的不同版本间的兼容性.如果你修改了此类, 要修改此值.否则以前用老版本的类序列化的 ...

  6. 软体定义网路(SDN)的多重意义

    SDN不需要传统的手动配置的静态定义的网络对象,SDN支持整个网络视图,通过在网络中添加或更改服务,自动配置设备.SDN以其将网络设置和配置(控制面)与数据包在网络中的实际移动(数据面)分离的能力,被 ...

  7. 数字化工厂的定义及建设目标和意义

    一.数字化工厂概述 数字化工厂是随着数字仿真技术和虚拟现实技术发展而来的,它通过对真实工业生产的虚拟规划.仿真优化,实现对工厂产品研发.制造生产和服务的优化和提升,是现代工业化与信息化融合的应用体现. ...

  8. C++ using namespace 命名空间的定义与使用

    #include <iostream> using namespace std;namespace A {int x, y;void fun() {cout << " ...

  9. C++ 笔记(03)— 命名空间(概念、定义、调用、using name 指令、嵌套命名空间)

    1. 命名空间概念 在 C++ 应用程序中, 您可能会写一个名为 func() 的函数,在另一个可用的库中也存在一个相同的函数 func() .这样,编译器就无法判断您所使用的是哪一个 func() ...

最新文章

  1. 博客园 cnblogs博客添加Google Analytics统计
  2. u盘安装centos8黑屏_崩溃!电脑突然黑屏无法启动
  3. 用步进正弦激励法测量计算机声卡输出输入幅值频响函数
  4. python怎么定义全局变量_python中如何定义全局变量
  5. PyTorch系列入门到精通——模型保存与加载
  6. 电子设计竞赛方案搜集
  7. 不懂Shopee站点分析,入驻Shopee平台哪个站点?
  8. mysql误删除数据恢复_mysql误删除数据恢复
  9. python 获取MP4视频第一帧 | Python工具类
  10. python中match方法中r什么意思_什么是pythonre.match函数?(实例解析)
  11. 28年蛰伏,易特驰打响「软件定义汽车」硬战
  12. 如何看待 Java 大厂 P6+ 这一岗位能力要求?
  13. opencart seo优化_OpenCart商品与目录页标题SEO优化
  14. 人眼识别与机器识别的联系_机器可以识别笑话吗
  15. 《C++游戏编程入门(第4版)》——1.10 问与答
  16. 惊险17分钟,这个阿里巴巴程序媛机智化解全局性重大故障
  17. 共享计算机后防火墙能开启,360防火墙在哪里设置 如何打开或关闭【图解】
  18. Linux内核-进程管理
  19. linux apktool,apktool · Kali Linux Tools Documents · 看云
  20. Android电池管理系统框架整理

热门文章

  1. 收益率曲线matlab,收益率曲线拟合技术解读.ppt
  2. Python为何如此受欢迎?你真的需要学习Python嘛?学了之后能做些什么?
  3. Oracle查询数据
  4. Intel突然补刀:PC电脑又悲催了
  5. java 修改图片dpi_java获取jpg图片的dpi和修改图片的dpi
  6. 中专学的计算机专业全名,中专是什么学历 有哪些专业可以选
  7. java empty_Java Optional empty()用法及代码示例
  8. RangeValidator1 日期验证格式
  9. python速成班1个月_Python速成班-基础篇DAY03
  10. 网络安全(三)——入侵和网络攻击