【C++】命名空间

news2024/10/7 19:22:47

🏖️作者:@malloc不出对象
⛺专栏:C++的学习之路
👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈
在这里插入图片描述

目录

    • 前言
      • 一、命名空间产生的背景
      • 二、命名空间的定义
      • 三、命名空间的使用
      • 四、从多个角度分析为什么不提倡使用using namespace
        • 4.1 如何合理使用using namespace std
        • 4.2 \<iostream> 与<iostream.h>的关系
      • 五、如何合理使用命名空间来避免命名冲突


前言

本篇文章将给大家讲述的是命名空间,它是C++中为了解决命名冲突所引申出的一种解决方案,我们使用C++常用的using namespace std;std就是C++标准库的命名空间名称,也许有小伙伴兴许还不知道这句代码表示什么含义,下面就让我们进行命名空间的学习吧!!

一、命名空间产生的背景

我们首先来看一个例子:

在这里插入图片描述

C++是向下兼容C语言的语法的,在这段代码中使用rand发生了重定义,因为在C中rand是头文件stdlib.h中的一种库函数,而现在我们将rand作为普通变量名来使用这就造成了重命名,编译器不知道到底使用哪个rand,而在C语言中只能通过更换名称来解决这种命名冲突,可这其实是一个非常蛋疼的问题。

大型应用程序经常使用来自不同厂商的开发库,几乎不可避免会使用相同的名字,也就是说一个库中定义的名字可能与其他库中的名字相同而产生冲突。假如不同的程序员分别定义了类和函数,放在了不同的头文件中,在主函数的文件中需要使用这些类和函数时,就用#include指令将这些头文件包含进来,我们知道在预编译后#include头文件会将头文件的内容展开在源文件中,这样就在同一个程序文件中可能就会出现了多个名字相同的类或函数,这就造成了命名冲突,即在同一个作用域中有两个或者多个同名的实体,使得程序员不能组合各自独立的开发库到一个程序中。

对此ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突。

命名空间是用来限定名字的解析和使用范围,它是C++开发大型程序的工具之一。命名空间的原理是将全局作用域划分为一个一个的命名空间,每个命名空间是一个独立的作用域,在不同命名空间内部定义的名字彼此之间互不影响,从而有效的避免了命名污染。

二、命名空间的定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。

下面就是一个简单的命名空间:

在这里插入图片描述

命名空间可以在全局作用域或其他命名空间内部定义,但不能在函数、结构体或类内部定义,且要保证命名空间之间不会出现名字冲突。
在命名空间作用域内,可以包含:变量、对象以及它们的初始化、枚举常量、函数声明以及函数定义、类、结构体声明与实现、模板、其他命名空间。每个命名空间是一个作用域,定义在命名空间中的实体称为命名空间成员,命名空间中的每个名字必须是该命名空间中的唯一实体,但不同命名空间可以具有同名成员。

// 1. 正常的命名空间定义
namespace Curry1
{
	// 变量、函数、结构体....
	int a;
	void func1()
	{
		//...
	}

	struct Node
	{
		struct Node* next;
		int val;
	};

	//...
}

// 2. 嵌套的命名空间定义
namespace Curry1
{
	// 变量、函数、结构体....
	int a;
	void func1()
	{
		//...
	}

	struct Node
	{
		struct Node* next;
		int val;
	};

	namespace Curry2
	{
		int b;
		void func2()
		{
			//...
		}
	}

	//...
}

// 3.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中
namespace Curry1
{
	// 变量、函数、结构体....
	int a;
	void func1()
	{
		//...
	}

	//...
}

namespace Curry1
{
	int b;
	int Add(int a, int b)
	{
		return a + b;
	}
	//...
}

注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。

三、命名空间的使用

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

第一种使用方式:命名空间名称::xxx

在这里插入图片描述

这种命名空间的方式是三种之中最繁琐的一种方式,因为它需要我们一个个去指定命名空间域,但同时它却是最安全的一种方式,它避免了命名空间被污染。

这个地方还有一种使用域运算符引用全局命名空间的成员的方式,下面我们简单的看一个例子:

在这里插入图片描述

::xxx 表示引用全局命名空间成员,我们可以这样来简单的理解一下,域运算符左边为空就代表全局命名空间域。所以 ::xxx就可以表示直接引用xxx全局命名空间成员。

下面这里再补充一下嵌套命名空间的使用方式,我们一起来简单的看下:

在这里插入图片描述


第二种:using 命名空间名称::xxx

在这里插入图片描述

将std C++标准库中经常使用的少数几个成员使用using 命名空间名称::xxx部分展开,使用一部分暴露一部分,这样在一定程度上也减少了命名空间被污染,到后面我个人也是偏提倡这种使用命名空间的方式。


第三种:using namespace 命名空间名称

在这里插入图片描述

using namespace Curry1将Curry1命名空间域中的内容全局展开,所以我们的变量a以及Add函数可以直接进行使用,,这种方式最为方便直接令整个命名空间成员都有效,但同时这种全局展开的方式是最不安全的,下面我会带大家详细探究这个问题。

四、从多个角度分析为什么不提倡使用using namespace

1.首先我们这里特别强调尤其不要在头文件中使用using namespace。

我们知道#include头文件会在预处理阶段将头文件的内容展开到源文件中,如果将using namespace包含在头文件中那么随着会在源文件中全局展开,那么此时的命名空间就被污染了,换而言之就是使用using namespace全局展开之后命名空间域就消失了,我们在.cpp中写的代码很有可能会与using namespace命名空间域中的变量、函数、类等发生重名冲突。
在大工程中如果出现此类问题是很难去追查错误源头的,尤其像有多个文件嵌套包含了using namespace,你该如何去进行追查错误源头?这无疑为我们带来了巨大的维护成本。

上述关于尽量不要在头文件中使用using namespace,这就话本质就是在 “尽量不扩大using namespace xxx所影响到的域”,所以我们可以写在cpp文件中使其控制在一个编译单元内,也可以写在函数里控制在一个函数中,这样都一定程度上控制了using namespace所影响到的域的范围。

对于在源文件中使用using namespace,有一部分大佬则是持开放的态度认为源文件中可以随便在源文件中使用using namespace,因为.cpp文件不影响他人的使用;而对于这一点我的看法还是不能在任何情况下滥用using namespace,在源文件中也会有一定的风险,下面我们来看一个例子:

在这里插入图片描述

上图例子由于A和B的命名空间域都是全展开的,此时编译器就不确定变量b到底使用哪个命名空间的。

同样的角度,假设命名空间A中定义了一个函数Add_1,命名空间B中定义了一个函数Add_2,它们两者全局展开,,此时我们即可以使用函数Add_1又可以使用函数Add_2,但是以后假设A命名空间升级了也加入了一个函数Add_2,那么这时候我们原来的代码就有问题了,我们编译器到底使用的是命名空间A的Add_2还是命名空间B的Add_2呢?此时就发生了命名冲突,如果是一个大工程的话,假设命名空间A就是我们的C++标准命名空间,命名空间B是公司成员写的代码,此时C++标准命名空间升级了,那么此时这个公司之前写的代码就跑不过去了,这样就带来很大的损失…

2. 其次使用using namespace与命名空间设计的初衷背道而驰了。

本身namespace就是给你一个限定名字域的作用的,但是你using之后就相当于没有了命名空间域,因为using namespace将这个命名空间域全部展开暴露在文件中了嘛!!更通俗的来讲站在命名空间的角度使用using namespace跟没使用是一样的!!!

这里可能有读者还不明白,这里我举一个例子:当你用C++标准库STL的cout时,同时引用了命名空间域A中的cout,此时编译器不知道你要用的是std::cout还是A::cout,所以要想避免命名冲突你还是得显式的写std::coutA::cout,这样看来using namespace是不是就没什么用了而且还带了一些麻烦。

Q:那么有读者可能会问那为啥要设计出using namespace这种使用命名空间的方式呢?

首先我认为设计者觉得在一些情况下使用using namespace是非常方便的,就如我们上个话题谈到的不涉及大量重名的、大型项目中的;其次也许设计者在设计时没考虑全展开重名呢,仅仅是觉得有些场景下使用起来方便所以设计出来的呢,,不管处于什么原因我认为存在即合理!!

总的来说,我认为不应该抹杀任何一种使用方式,我们只是站在不同的角度去辩证的看待这三种方式带来的问题。

4.1 如何合理使用using namespace std

通过上述我们对using namespace做的一系列分析,我们也知道要尽量使用using namespace全局展开,std是C++标准库的命名空间,如何展开std使用更合理呢?

1.在日常练习中,建议直接using namespace std即可,这样就很方便。
2.using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现,所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 +using std::cout展开常用的库对象/类型等方式。

4.2 <iostream> 与<iostream.h>的关系

在我们之前的C语言学习当中,我们见到的想必都是.h头文件这种形式,但是在C++引入命名空间之后,C++新的标准为了和C区别开来规定头文件不使用后缀.h,另外C++为了兼容C,在C++标准化过程中,原有C语言头文件标准化后头文件名前带个c,例如cstdio、cstring、cstdlib等…

Q:那么在C++新的标准中<iostream>与<iostream.h>一样吗?

答案是不一样,这俩者是两个不同的文件,当使用<iostream.h>时相当于在C中调用库函数,使用的是全局命名空间,也就是早期C++的实现;当使用<iostream>时,该文件没有定义全局命名空间必须加上using namespace std;这样才能使用C++标准库中的类、函数等…这也就是我们经常写.cpp时通常头文件和using namespace std;缺一不可的原因。

五、如何合理使用命名空间来避免命名冲突

一般情况下,对偶尔使用命名空间的成员应该使用命名空间的作用域解析运算符来直接给名称定位,这是最为安全的一种方式;而对一个大空间中经常要使用的少数几个命名空间成员提倡使用using 命名空间名称::声明,我个人也是偏提倡一点这种使用方式,对于少数几个命名空间成员来讲它污染的命名空间域范围较小,因为毕竟第一种方式确实对于一个繁琐使用的少数命名空间成员不是很友好;对于最后一种using namespace全展开命名空间域其实是最不提倡使用的,因为它会带来很多风险。但对于现阶段的我们来说,在平时的一些练习、竞赛以及项目小没有很多重名的时候,我们使用using namespace是可行的,因为它确实很方便并不需要我们过多去考虑命名冲突的风险,但使用using namespace终究还是有未知的风险的,我们不要在平时太依赖using namespace这种命名方式了。糖果虽甜,但吃多了就会有蛀牙🙈🙈

对于以后自己参加工作编写项目时,我个人的看法是将自己写的函数、类放在自己的命名空间,使用的时候不管是哪个命名空间里的,都要指明出处,都不要全部展开!!!因为你不知道什么时候风险会降临到你身边orz~


本篇文章的讲解就到这里了,如果有任何错处或者疑问欢迎大家评论区交流哦~~ 🙈 🙈

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

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

相关文章

【一天时间|简历模板】世界上最好的前端简历

一天时间系列文章是博主精心整理的面试热点问题和难点问题&#xff0c;吸收了大量的技术博客与面试文章&#xff0c;总结多年的面试经历&#xff0c;带你快速并高效地审视前端面试知识。直击技术痛点&#xff0c;主动出击&#xff0c;精密打击&#xff0c;这才是面试拿到高薪的…

网络基础知识(IP地址、TCP协议/IP协议、UDP协议、三次握手,四次挥手的过程、端口等的概念)

TCP/IP 协议 首先给大家说明的是&#xff0c;TCP/IP 协议它其实是一个协议族&#xff0c;包含了众多的协议&#xff0c;譬如应用层协议 HTTP、FTP、MQTT…以及传输层协议 TCP、UDP 等这些都属于 TCP/IP 协议。 所以&#xff0c;我们一般说 TCP/IP 协议&#xff0c;它不是指某…

unity-与js交互

title: unity-与js交互 categories: Unity3d tags: [unity, js, web, h5] date: 2023-03-05 00:09:52 comments: false mathjax: true toc: true unity-与js交互 前篇 官方 WebGL&#xff1a;与浏览器脚本交互 - https://docs.unity3d.com/cn/2021.1/Manual/webgl-interacting…

JavaWeb--JSP

JSP1 JSP 概述2 JSP 快速入门2.1 搭建环境2.2 导入 JSP 依赖2.3 创建 jsp 页面2.4 编写代码2.5 测试3 JSP 原理4 JSP 脚本4.1 JSP 脚本分类4.2 案例4.2.1 需求4.2.2 实现4.2.3 成品代码4.2.4 测试4.3 JSP 缺点5 EL 表达式5.1 概述5.2 代码演示5.3 域对象6 JSTL标签6.1 概述6.2 …

Android应用启动优化笔记整理

应用启动相关流程与优化 应用启动主要涉及SystemServer进程 和 app进程。 SystemServer进程负责app进程创建和管理、窗口的创建和管理&#xff08;StartingWindow 和 AppWindow&#xff09;、应用的启动流程调度等。 App进程被创建后&#xff0c;进行一系列进程初始化、组件初…

【LinkedList】| 深度剥析Java SE 源码合集Ⅰ

目录一. &#x1f981; LinkedList介绍二. &#x1f981; 结构以及对应方法分析2.1 结构组成2.1.1 节点类2.1.2 成员变量2.2 方法实现2.2.1 添加add(E e)方法2.2.2 头尾添加元素Ⅰ addFirst(E e)Ⅱ addLast(E e)2.2.3 查找get(int index)方法2.2.4 删除remove()方法三. &#x…

【云原生】整合K8s + SpringCloudK8s + gRpc + RocketMQ + Istio + Envoy

背景本文把前面的代码整理一遍&#xff0c;不仅仅是demo层面&#xff0c;而是考虑到放进生产中使用&#xff0c;且尽可能用高版本&#xff0c;关于这块技术&#xff0c;网上的文章真是一言难尽&#xff0c;要么就是个概念&#xff0c;要么就是把官网的demo拿过来跑一遍&#xf…

图神经网络 pytorch GCN torch_geometric KarateClub 数据集

图神经网络 安装Pyg 首先安装torch_geometric需要安装pytorch然后查看一下自己电脑Pytorch的版本 import torch print(torch.__version__) #1.12.0cu113然后进入官网文档网站 链接: https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html 安装自己…

【小破站下载工具】Python tkinter 实现网站下载工具,所有数据一键获取

目录前言开发环境本次项目案例步骤先展示下完成品的效果界面导入模块先创建个窗口功能按键主要功能代码编写功能一功能二功能三前言 最近很多同学想问我&#xff0c;怎么把几个代码的功能集合到一起&#xff1f; 很简单&#xff0c;写一个界面就行了&#xff0c;想要哪个代码…

黑马程序员7

算数运算符重载 运算符重载概念&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 加号运算符 通过自己写函数&#xff0c;实现两个对象相加属性后返回新的对象 两种方式重载 成员函数方式重载 全局函数重载 上来 perso…

Go 内存分布

Go内存分布方式在C中&#xff0c;每个值在内存中只占据一个内存块&#xff08;一段连续内存&#xff09;&#xff1b;但是&#xff0c;一些Go类型的值可能占据多个内存块。以后&#xff0c;我们称一个Go值分布在不同内存块上的部分为此值的各个值部&#xff08;value part&…

网络安全平台测试赛 easyphp(phar脏数据处理)

昨天的比赛&#xff0c;14.00-17.00.时间有点紧张&#xff0c;比赛期间没拿下来这道 &#x1f62d;非常痛苦&#xff0c;很顺畅的思路 一步步想下来&#xff0c;卡在最后一步末尾脏数据处理了&#xff0c;最后时间到了 没打通&#xff0c;还需多练 这里本地复现一下&#xff1…

linux 进程及调度基础知识

引用Linux进程管理专题Linux进程管理与调度-之-目录导航Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度&#xff08;五&#xff09;蜗窝科技-进程管理郭健&#xff1a; Linux进程调度技术的前世今生之“前世”郭健&#xff1a; Linux进程调度技术…

1.7 古典概型问题类型一——随机取数问题

(1)我的答案&#xff1a;一、信息首先7个数字全不相同二、分析七个数字全不相同意味着每次取出来的数都不一样&#xff0c;然后每次取出后选择少一种&#xff0c;为简单排列不含10和1这意味从8个数里面选且可以重复为重复排列3.10恰好出现两次隐含着两个问题&#xff0c;第一&a…

备考考研2数学

进度说明&#xff0c;开始形成自己的复习进度说明&#xff01; 14:21 2023年2月28日星期二 武忠祥数学 截止目前&#xff0c;看完了01.高数基础01 14:21 2023年2月28日星期二 开始看02. 现在15:04 2023年2月28日星期二&#xff0c; 因为这2天的百度网盘不能进行解析了&…

初识HTML技术

文章目录一、为什么学习前端?二、第一个HTML文件VSCode三. HTML元素四. HTML页面一、为什么学习前端? 我们作为一个后端程序员&#xff0c;为什么还要学习前端&#xff0c;因为我们的终极目的是实现web开发&#xff0c;搭建网站&#xff0c;网站 前端 后端 比如我们随便…

最近几篇较好论文实现代码(附源代码下载)

《Towards Layer-wise Image Vectorization》(CVPR 2022) GitHub: github.com/ma-xu/LIVEInstallationWe suggest users to use the conda for creating new python environment.Requirement: 5.0<GCC<6.0; nvcc >10.0.git clone gitgithub.com:ma-xu/LIVE.gitcd LIVE…

一步一步学会给Fritzing添加元器件-丰富你的器件库

文章目录1、获取元器件文件2、单个添加元器件3、批量加入&#xff08;1&#xff09;、通过别人发布的bin文件加载&#xff08;2&#xff09;、终极大招&#xff08;拖&#xff09;4、制作自己器件文章出处&#xff1a; https://blog.csdn.net/haigear/article/details/12931545…

【C++】类和对象——六大默认成员函数

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、类的6个默认成员函数二、构造…

错误异常捕获

1、React中错误异常捕获 在 React 中&#xff0c;可以通过 Error Boundaries&#xff08;错误边界&#xff09;来捕获错误异常。Error Boundaries 是一种 React 组件&#xff0c;它可以在其子组件树的渲染期间捕获 JavaScript 异常&#xff0c;并且可以渲染出备用 UI。React 提…