C++ -命名空间-详解

博客主页:【夜泉_ly】
本文专栏:【C++】
欢迎点赞👍收藏⭐关注❤️

C++ -命名空间-详解

  • 1.C语言缺点之一 -- 命名冲突
  • 2.命名空间
    • 2.1定义
    • 2.2使用
      • 访问命名空间中的变量
      • 展开命名空间域
      • 指定访问命名空间域
    • 2.3其他功能
  • 3.C++ 标准库中的命名空间
    • 指定展开
  • 4.总结

1.C语言缺点之一 – 命名冲突

先来看看下面这段简单的C语言代码:

#include <stdio.h>
int rand = 0;
int main()
{printf("%d\n", rand);return 0;
}

运行结果如下:

0

毫无疑问的结果对吧,那如果我再引入这样一个头文件呢:

#include <stdlib.h>

运行结果如下图:
在这里插入图片描述
报错了 ! 原因呢?
在这里插入图片描述
命名冲突 ——如果学过C语言,那应该能知道在<stdlib.h>里面有一个函数,用于生成随机数,而这个函数的名字就是rand,此处,我也定义了同名的变量rand,这就导致了命名冲突。

在C语言中,全局域中命名冲突非常常见,主要有以下两种情况:
1.与库函数冲突:
这就是上面代码报错的原因。
在C语言项目中,可能某天引入了一个库,结果出现了一大堆冲突。
2.开发者相互之间冲突:
在大型项目中,往往都是项目组,这代表不是一个人在写。
那么有没有一种可能,张三写的和李四写的冲突了,但在他们电脑上都能跑。有一天,不同模块合并到一起,结果发现冲突了,这时必然会有一个人要改他的代码。
如果张三、李四都将这个名字在他们的代码里用了几百上千词,那么要修改将是一个极其痛苦的事情。

而C++的祖师爷,下图的本贾尼·斯特劳斯特卢普,同样受够了C语言中的这个缺点,于是在C++中,创造了一个关键字namespace ,用来解决全局域中命名冲突的问题。
在这里插入图片描述

2.命名空间

2.1定义

命名空间可以定义出一个,将其中的内存隔离在这个独立区域,不会与其他区域中的名字冲突:

namespace ly
{int rand = 0;
}

在上面的代码中,我定义了一个名为ly的命名空间,里面包含了变量rand。通过这种方式,避免了与标准库rand函数的冲突。

此处,ly是命名空间的名字,这里我取的是我博客名字【夜泉_ly】中的一部分,而一般开发中是用项目名字做命名空间名。

2.2使用

访问命名空间中的变量

在C语言的学习中,可以了解到,同一个域不能定义同名变量,而不同的域可以定义同名变量。
例如,全局作用域和局部作用域:

#include <stdio.h>
int a = 0;//全局域--全局变量
int main()
{int a = 1;//局部域--局部变量printf("%d\n", a);return 0;
}

C语言的域会影响生命周期,也会影响访问,比如上面这段代码的运行结果是1,因为优先访问的是局部变量。
那么有人问了,如果我就想访问全局变量呢?
也是有方法的:

#include <stdio.h>
int a = 0;//全局域--全局变量
int main()
{int a = 1;//局部域--局部变量printf("%d\n", ::a);return 0;
}

这里使用了域作用限定符::,其作用是对左边的域进行访问,此处::左边没有域,即左边为空白,代表对全局域进行访问。
再看下面这种情况:

#include <stdio.h>
int a = 0;//全局域--全局变量
namespace ly
{int a = 2;//命名空间域
}
int main()
{int a = 1;//局部域--局部变量printf("%d\n", a);return 0;
}

这里出现了三种域,局部域、全局域、命名空间域,按什么顺序访问?
第一次打印,结果为1,因为默认局部域优先。
再注释掉局部变量a:

//int a = 1;//局部域--局部变量

第二次打印,结果为0,因为局部域未找到指定变量时,会去全局域找。
再注释掉全局变量a:

//int a = 0;//全局域--全局变量

第三。。没有第三次打印了:
在这里插入图片描述
又报错了 ! 原因呢?
在这里插入图片描述
未声明a ——这是因为编译器并不会主动去命名空间域中搜索,所以会报错。
如何访问命名空间域呢?
一般而言,有两种方法:展开命名空间域 OR 指定访问命名空间域。

展开命名空间域

使用using关键字:

using namespace ly;

在一些C++程序开头,常常看见下面这两句代码:

#include <iostream>
using namespace std;

现在可以知道第二句在干什么了:展开了C++标准库的命名空间域。

指定访问命名空间域

printf("%d\n",ly::a);

即在域作用限定符::前加上要访问的命名空间。


现在使用第一个方法,展开命名空间域,来看看下面这段代码会输出什么值?😄

#include <stdio.h>
int a = 0;//全局域--全局变量
namespace ly
{int a = 2;//命名空间域
}
using namespace ly;//展开命名空间域
int main()
{printf("%d\n", a);return 0;
}

什么都输出不了!又报错了:
在这里插入图片描述
其实此处的两个a又冲突了:
展开命名空间域,是将命名空间域中的内容全部暴露到全局域,而同一个域不能定义同名变量,所以编译器会报错。
因此,不要轻易使用using namespace!


回到开头,如果想放心的使用rand作为变量名,可以使用命名空间,并通过指定访问命名空间域的方式访问:

#include <stdio.h>
#include <stdlib.h>
namespace ly
{int rand = 0;
}
int main()
{printf("%d\n", ly::rand);//打印rand变量的值printf("%p\n", rand);//打印rand函数的地址return 0;
}

此时可以成功输出结果,如图:
在这里插入图片描述

或许会有人问:为什么不能定义一个局部变量来解决问题?
需注意的是,此处的问题就是定义了一个全局变量,而这个全局变量与库冲突了。因此不能通过定义局部变量解决问题。


2.3其他功能

除了变量,命名空间还可以包含其他内容,例如函数、结构体等。
命名空间甚至可以嵌套使用:

namespace N1
{int a = 1;namespace N2{int a = 2;}
}

访问时也需多次使用::

printf("%d\n",N1::N2::a);//输出2

通过嵌套命名空间,开发者可以进一步组织和管理代码。


3.C++ 标准库中的命名空间

在学习C语言时,有时也会看到一些C++的代码,这时或许会产生疑问,为什么C++无.h,比如:

#include <iostream.h>

其实,在很早之前,上面这句代码是存在的,在一些老编译器(如VC6.0)上也可以运行,但那时没有命名空间,也不需要展开。

而后来为了与C语言进行区分,并且有了命名空间,C++库、STL等被封进std,这时.h就被去掉了。

现在,标准库通过std命名空间进行管理,在 C++ 的标准库中,所有的库函数和对象都封装在 std 命名空间中。
又由于默认不去命名空间进行搜索,在使用标准库时,可以选择指定访问,例如:

std::cout << "Hello World!" << std::endl;

或者展开空间:

using namespace std;
cout << "Hello World!" << endl;

需注意:这个展开并非展开头文件,因此,展开std不等于不包含头文件!!

在包含了头文件后,在预处理阶段会将其内容展开,而其内容是封在std里的,展开了std,等于告诉编译器可以去这些内容里面进行搜索。
但是,直接展开会有风险,如果自己定义的跟库重名,就会报错,这不就直接回到起点,将C语言的缺点再次包含。
因此,建议在项目中不要展开,而是指定访问;而日常练习中可以展开

而在一个项目中,可能会有百万级的代码量,每次都指定访问太过麻烦,这里就出现了一种新的玩法:

指定展开

例如:

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

只需将常用的展开,不常用的再指定访问,就能大大减少工作量。

4.总结

命名空间是 C++ 中用于解决命名冲突的一个非常重要的工具。
在编写大型项目时,开发者应尽量避免直接展开整个命名空间,而是通过指定访问或部分展开的方式来使用命名空间。
合理使用命名空间不仅能提高代码的可维护性,还能避免命名冲突带来的问题。


希望本篇文章对你有所帮助!并激发你进一步探索编程的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1538715.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

ChartLlama: A Multimodal LLM for Chart Understanding and Generation论文阅读

原文链接&#xff1a;https://arxiv.org/abs/2311.16483 代码与数据集&#xff1a;https://tingxueronghua.github.io/ChartLlama/ 本文启发&#xff1a;文章提出利用GPT-4合成大量图表数据&#xff0c;这些数据包含各种图表类型&#xff0c;包含丰富的instruction data。然后…

SpringBootWeb增删改查入门案例

前言 为了快速入门一个SpringBootWeb项目&#xff0c;这里就将基础的增删改查的案例进行总结&#xff0c;作为对SpringBootMybatis的基础用法的一个巩固。 准备工作 需求说明 对员工表进行增删改查操作环境搭建 准备数据表 -- 员工管理(带约束) create table emp (id int …

[产品管理-25]:NPDP新产品开发 - 23 - 产品创新中的市场调研 - 定量市场调研的常见工具

目录 前言&#xff1a; 一、问卷调查 二、消费者测评组 三、概念测试与概念分类 概念测试 概念分类 四、感官检验 1、定义与特点 2、基本方法 3、应用领域 4、优势与局限性 五、眼动追踪 1、技术原理 2、应用领域 3、技术优势 4、市场现状与发展趋势 5、结论 …

创建github的个人主页

创建同名仓库 展示 github star 等信息 https://github.com/anuraghazra/github-readme-stats 添加贪吃蛇 https://github.com/Platane/snk?tabreadme-ov-file 配置好了之后 run workflow 即可

总结拓展十:SAP开发计划(上)

第一节 功能开发说明书介绍 1、功能开发的基础分类 报表查询开发单据打印开发功能开发增强开发接口开发 2、屏幕元素介绍 ——程序屏幕是SAP系统与用户之间的桥梁&#xff0c;屏幕由各种不同元素布局组成 示例&#xff1a;选择屏幕界面 单选输入框 多选输入框 设定默认…

.Net Core 生成管理员权限的应用程序

创建一个ASP.NET Core Web API项目 给解决方案设置一个名称 选择一个目标框架&#xff0c;这里选择的是 .NET 8.0框架 在Porperties文件夹中添加一个app.manifest文件 设置app.manifest文件属性&#xff0c;生成操作设置为嵌入的资源 双击解决方案名称&#xff0c;编辑WebAppli…

FP6296XR-G1 10A电流模式非同步PWM升压转换器芯片IC

一般说明 F1 6296是目前最先进的直流一直流转换器。是一个带有内置15mΩ功率MOSFET使此稳压器具有高功率效率。误差放大器的非逆变输入端连接到1.2V的精密基准电压。电流模式控制和外部补偿网络使系统稳定容易灵活。FP6296采用SOP-8L(EP)封装&#xff0c;可用于应用领域…

使用rust自制操作系统内核

一、系统简介 本操作系统是一个使用rust语言实现&#xff0c;基于32位的x86CPU的分时操作系统。 项目地址&#xff08;求star&#xff09;&#xff1a;GitHub - CaoGaorong/os-in-rust: 使用rust实现一个操作系统内核 详细文档&#xff1a;自制操作系统 语雀 1. 项目特性 …

【ArcGISPro】配置模块

ArcGIS Pro 配置类似于加载项&#xff0c;但提供了扩展应用程序的其他方法。它可以帮助您设计更贴近您组织品牌和工作流的 ArcGIS Pro 版本。 托管配置是比 Add-in 更高级别的自定义。 配置可以提高加载项安全级别并添加非管理员指定的已知文件夹。 配置可以提供比插件更广泛…

如何使用麦肯锡方法做软件需求分析?

使用麦肯锡方法进行软件需求分析&#xff0c;可以借鉴其结构化思维、逻辑严密、以结果为导向的特点&#xff0c;来确保需求分析过程的高效性、准确性和全面性。 一、定义问题与目标 明确项目背景&#xff1a; 了解软件开发的目的、业务场景、用户需求等背景信息。 分析市场趋势…

数据结构——二叉搜索树、Map和Set

对于不同的数据结构&#xff0c;他们的使用场景是不一样的&#xff0c;map和set这两种数据结构主要用在搜索相关的场景中。学习这些之前我们先来了解一下二叉搜索树&#xff0c; 一、搜索树 1.1概念 二叉搜索树 又称 二叉排序树 &#xff0c;它或者是一棵空树&#xff0c;或者…

【Java】线程的同步——synchronized、ReentrantLock

对同一个线程&#xff0c;能否在获取到锁以后继续获取同一个锁? 答案是肯定可以获取同一个锁。因为JVM 允许同一个线程重复获取同一个锁&#xff0c;这种能被同一个线程反复获取的锁&#xff0c;就叫做可重入锁。 一、synchronized同步锁 在 Java中synchronized 同步锁…

开放的数据时代:Web3和个人隐私的未来

在数字化和信息化的时代&#xff0c;数据隐私成为了公众关注的焦点。随着Web3技术的兴起&#xff0c;个人隐私保护进入了一个新的阶段。Web3作为去中心化的互联网架构&#xff0c;提出了对数据控制和隐私保护的新方案。本文将探讨Web3如何影响个人隐私的未来&#xff0c;并分析…

Vue3中的Pinia——管理应用程序的全局状态

介绍Pinia Pinia 是 Vue.js 的状态管理库&#xff0c;主要用于管理应用程序的全局状态。它是 Vuex 的替代品&#xff0c;提供了更简单和更灵活的 API。Pinia 的主要作用包括&#xff1a; 1. 状态管理&#xff1a;Pinia 允许你在应用中集中管理状态&#xff0c;方便不同组件之…

leetcode:验证回文串

[题目链接] string func(string s)//先将大写转换成小写&#xff0c;并且去除空格等&#xff0c;只保留小写字母 {string tmp;string::iterator it s.begin();while (it ! s.end()){//大写字母if (*it < 90 && *it>65)//A-Z的ASCII码为65-90{tmp *it 32;//a-z…

Redis存储原理

前言 我们从redis服务谈起&#xff0c;redis是单reactor&#xff0c;命令在redis-server线程处理。还有若干读写IO线程负责IO操作&#xff08;redis6.0之后&#xff0c;Redis之pipeline与事务&#xff09;。此外还有一个内存池线程负责内存管理、一个后台文件线程负责大文件的关…

大数据Flink(一百一十八):Flink SQL水印操作(Watermark)

文章目录 Flink SQL水印操作&#xff08;Watermark&#xff09; 一、为什么要有WaterMark 二、​​​​​​​​​​​​​​Watermark解决的问题 三、​​​​​​​​​​​​​​代码演示 Flink SQL水印操作&#xff08;Watermark&#xff09; 一、​​​​​​​为什么…

《黑神话悟空》黄眉打法技巧图文攻略详解

​黄眉是黑神话悟空第三章的关底的boss&#xff0c;很多的玩家都非常的好奇这个boss到底要怎么打&#xff0c;这里小编就为大家带来了黄眉这个boss的打法&#xff0c;我们不要使用法术&#xff0c;只使用禁字诀就可以击败这个boss&#xff0c;详细的内容可以在这里进行了解和查…

DevEco Profiler调优工具(二)

一、Profiler调优模板 3、Snapshot Insight 4、CPU Insight 5、Frame Insight 6、Launch Insight

硬件(驱动开发)

一、OSC基本架构&#xff08;片上系统&#xff09; OSC&#xff08;On-chip System Control&#xff0c;片上系统控制&#xff09;基本架构通常涉及片上系统中的各个组件如何进行协调与控制&#xff0c;以实现高效的处理、通信和管理。OSC架构在现代微处理器和系统单芯片&…