C++_命名空间(namespace)

news2024/11/20 1:31:04

        

目录

1、namespace的重要性

2、 namespace的定义及作用

2.1 作用域限定符

 3、命名空间域与全局域的关系

4、命名空间的嵌套

 5、展开命名空间的方法

5.1 特定展开

5.1 部分展开

5.2 全部展开

结语:


前言:

        C++作为c语言的“升级版”,其在语法上相对于c语言有了诸多升级、优化,比如在C++中有一个全新的概念:命名空间(namespace)。在使用C++时,该语法很好的解决了对标识符命名重名的问题。

1、namespace的重要性

        在使用c语言写代码时,常常会遇到标识符命名重名的问题。比如我们自己写了一个函数,该函数名可能与库函数中的某个函数发生重名,或者与他人一起写项目时,也存在与他人代码中的标识符同名的现象,然而以上情况的解决方法只有对标识符进行改名。

        举例说明:

#include <stdio.h>
#include <time.h>
int time = 12;

int main()
{
	printf("%d\n", time);
	return 0;
}
//程序编译时会报错,原因是预处理阶段会展开全部的头文件(.h文件)
//被展开头文件里面的内容是具有“全局性的”,即全局都能使用里面的内容
//然而time.h的文件中存在一个名为time的函数
//在编译阶段,编译器会发现全局中有两个time的名称,并且报错

        因此针对重定义、重命名的这类问题,C++就提出了一个新的概念namespace。

2、 namespace的定义及作用

        namespace又称命名空间,他是一块独立于全局范围内的区域,在namespace区域中定义各种标识符的名称和全局中是分割开的,换句话说就是对命名空间内的标识符名称进行本地化管理,这样就不会与全局作用域中的同名标识符起冲突了。

        比如,创建两个头文件first.h和second.h,并且把这两个头文件都包含到主函数文件main.cpp中:

//first.h文件:
#pragma once
int a = 10;


//second.h文件:
#pragma once
int a = 101;


//main.cpp文件:
//包含上述两个.h文件
#include"first.h"
#include"second.h"
#include<stdio.h>

int main()
{
	printf("%d ",a);//a重定义了
	return 0;
}

//会报错:a重定义

        上述代码若运行,则会发生编译报错,原因就是再展开这两个头文件后,会出现两个a多重定义的报错。这时候可以将其中一个头文件的变量a换另一个名称,或者main.cpp中只包含其中一个头文件。但是如果这两个文件都要包含而且也不想对变量a的名称进行更改,那么只能用namespace将两个头文件下的变量a存到命名空间内。

2.1 作用域限定符

        使用namespace进行对上述代码的优化:

//first.h文件:
#pragma once
namespace first//namespace用法:namespace+自定义名称
{
	int a = 10;

}


//second.h文件:
#pragma once
namespace second
{
	int a = 101;

}


//main.cpp文件:
//包含上述两个.h文件
#include"first.h"
#include"second.h"
#include<stdio.h>

int main()
{
	printf("%d ", second::a);//::表示作用域限定符,左边跟作用域名称
	return 0;
}

//会报错:a重定义

        上述代码则将两个头文件下的变量a都放在了两块不一样的命名空间内,这样一来他们的名称就不会互相干涉了,只不过在使用变量a的时候要多一个步骤:使用作用域限定符去特指的命名空间查找。因为编译器也不知道程序员需要用哪个a,所以程序员需要在使用的a的左边加上“::”符号,并且在“::”符号的左边加上命名空间的名称,这样就可以精确的使用某个命名空间里的内容了,也称展开命名空间。

        上述代码运行结果:

 3、命名空间域与全局域的关系

        如果上文中的代码没有对a使用“second::”,会出现什么样的后果呢?

        可以发现编译器显示找不到变量a了,因为编译器查找的顺序是先找局部、再找全局,并不会自动的去命名空间内查找,所以全局域和命名空间域是分开的两个区域。因此在上述代码中,当头文件里的变量a被存放在命名空间中,可以理解为该变量从全局域被移动至命名空间域。

        关系图:

        比如全局域和局部域都有一个名为a的变量,如果编译器在局部域中就找到了a,则编译器会直接调用该a的值,并且也不会去全局域中查找,用上述代码进行变形当作例子:

#include"first.h"
#include"second.h"
#include<stdio.h>

int a = 1021;//全局变量

int main()
{
	int a = 22;//局部变量
	printf("%d ", a);
	return 0;
}

         运行结果:

        可以看到编译器直接选用了局部变量a作为打印结果。并且我们新加了全局变量int a=1021,编译器也没有报重命名的错误,说明全局域和命名空间域是分开的的两个区域,在全局域中定义了一个a,则命名空间域也能使用a的名称。

4、命名空间的嵌套

         命名空间的嵌套就是在该空间内在创建一个命名空间,一般是防止最外层命名空间的名称与别的空间同名,写法如下:

//first.h
#pragma once
namespace first
{
	namespace A
	{
		int a = 10;
	}
}

//second.h
#pragma once
namespace first//假设两个头文件下的第一层空间重名
{
	namespace B//则需要第二层空间来区别a变量
	{
		int a = 101;
	}
}


//main.cpp
#include"first.h"
#include"second.h"
#include<stdio.h>

int a = 1021;

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

        运行结果:

 5、展开命名空间的方法

        展开命名空间就是从命名空间内读取内容,上文提到的作用域限定符就是其中的一个办法,但是如果读取大量的内容就会很麻烦,因为只要是每一次读取都要加上作用域限定符,会很繁琐。因此另两种方法是部分展开和全部展开。

5.1 特定展开

        特定展开就是上文的展开方式,既:空间名称::变量名称。值得一提的是,使用特定展开时,编译器不会去局部和全局找,而是直接到命名空间内找,因此就算全局也有与该变量一模一样的名称,也不会报错,而且编译器还是会调用命名空间内的变量。

        特定展开代码如下:

//first.h
#pragma once
namespace first
{
	int a = 10;
}

//second.h
#pragma once
namespace second
{
	int a = 101;
}


#include"first.h"
#include"second.h"
#include<stdio.h>
int a = 1021;

int main()
{
	printf("%d\n", first::a);//编译器会调用first文件中的a,而不是调用全局a=1021的a
	return 0;
}

         运行结果:

5.1 部分展开

        在全局处使用using+空间名称::变量名称。部分展开与特定展开就不一样了,部分展开是把要调用的变量移动到全局域中,然后编译器在全局域中找到该变量,并不是让编译器指定到该空间去找,因此要保证全局中不能出现与该变量一样的名称,不然会报错。

        部分展开逻辑图如下:

        具体代码如下:

//first.h
#pragma once
namespace first
{
	int a = 10;
}

//second.h
#pragma once
namespace second
{
	int a = 101;
}

//main.cpp
#include"first.h"
#include"second.h"
#include<stdio.h>
using first::a;//展开first空间并且只调用a
//int a = 1021;//注意这时候first.h里的变量a属于全局变量了,不能再定义额外名称的a的变量

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

        运行结果:

         在全局处加上了using first::a,之后所有需要调用a变量的代码前面都不需要再加作用域限定符了。但是仅仅限于变量a不用加限定符,如果要调用first空间内其他的变量还是要加作用域限定符的,因此又引出一个新的概念:全部展开,全部展开某个命名空间,则后续的代码可以不加限定符直接调用该空间内的所有内容。

5.2 全部展开

        在全局处加上using+namespace+要展开空间的名称,既可对该空间进行全部展开。全局展开也同部分展开逻辑一样,全局展开相当于把该空间里的所有内容都移到全局域中,因此全局域中不能出现与该空间内有标识符名称相同的情况。

        全部展开代码如下:

//first.h
#pragma once
namespace first
{
	int a = 10;
	int b = 123;
	int c = 456;
}

//second.h
#pragma once
namespace second
{
	int a = 101;
}

//main.cpp
#include"first.h"
#include"second.h"
#include<stdio.h>
using namespace first;
//int a = 1021;

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

        运行结果:

        从结果来看,当全部展开first空间后,可以随意使用该空间的内容而且无需添加任何条件。 

结语:

        以上就是关于C++中命名空间的介绍,对于命名空间的全部展开其实在一般的情况下是不推荐的,因为全部展开意味着空间内的所有内容都变成了全局的,很容易发生重名,也就失去了命名空间防止重名的意义。

        最后希望本文可以给你带来更多的收获,如果本文对你起到了帮助,希望可以动动小指头帮忙点赞👍+关注😎+收藏👌!如果有遗漏或者有误的地方欢迎大家在评论区补充~!!谢谢大家!!( ̄︶ ̄)↗ 

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

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

相关文章

深度模型训练时CPU或GPU的使用model.to(device)

一、使用device控制使用CPU还是GPU device torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 单GPU或者CPU.先判断机器上是否存在GPU&#xff0c;没有则使用CPU训练 model model.to(device) data data.to(device)#或者在确定有GPU的…

帆软报表决策报表改变屏幕大小后出现字体大小或滚动条异常解决方案:双向自适应

帆软报表决策报表改变屏幕大小后出现字体大小或滚动条异常。 解决方案&#xff1a;在模板和报表块中配置双向自适应 在每一个报表块中设置&#xff1a;

【C/PTA —— 15.结构体2(课外实践)】

C/PTA —— 15.结构体2&#xff08;课外实践&#xff09; 7-1 一帮一7-2 考试座位号7-3 新键表输出7-4 可怕的素质7-5 找出同龄者7-6 排队7-7 军训 7-1 一帮一 #include<stdio.h> #include<string.h>struct student {int a;char name[20]; };struct student1 {int …

Java基础50题: 21.实现一个方法printArray, 以数组为参数,循环访问数组中的每个元素,打印每个元素的值.

概述 实现一个方法printArray, 以数组为参数,循环访问数组中的每个元素,打印每个元素的值. 代码 public static void printArray(int[] array) {for (int i 0; i < array.length; i) {System.out.println(array[i] " ");}System.out.println();}public static…

MySQL-日期时间函数详解及练习

目录 3.1 返回当前日期 3.2 提取日期部分 3.3 增加或减去时间 3.4 格式化时期或时间 3.5 牛客练习题 3.1 返回当前日期 1. CURDATE() 或 CURRENT_DATE() | 返回当前日期 select curdate();select current_date(); 结果&#xff1a; 2. CURTIME() 或 CURRENT_TIME() | 返…

CopyOnWriteArraySet怎么用

简介 CopyOnWriteArraySet是一个线程安全的无序集合&#xff0c;它基于“写时复制”的思想实现。它继承自AbstractSet&#xff0c;可以将其理解成线程安全的HashSet。 CopyOnWriteArraySet在读取操作比较频繁、写入操作相对较少的情况下可以提高程序的性能和可靠性。它的线程…

Win10 安装.NET Framework 3.5 报错0x80240438

环境&#xff1a; Win10专业版 NET Framework 3.5 问题描述&#xff1a; Win10 安装.NET Framework 3.5 报错0x80240438 解决方案&#xff1a; 1.检查自动更新服务是否未开启&#xff0c;开启自动更新失败&#xff0c;用工具开启自动更新,重启电脑&#xff08;未解决&am…

SAP UI5 walkthrough step2 Bootstrap

我的理解&#xff0c;这就是一个引导指令 1.我们右键打开命令行--执行 ui5 use OpenUI5 2.执行命令&#xff1a;ui5 add sap.ui.core sap.m themelib_sap_horizon 执行完之后&#xff0c;会更新 yaml 文件 3.修改index.html <!DOCTYPE html> <html> <head&…

学习spring、springmvc、mybatis、ssm所有可能用到的依赖总结,父工程pom文件依赖,<packaging>pom</packaging>

1、父工程pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/PO…

VR转接线方案/VR Link串流数据线方案/VR眼镜PD快充方案

虚拟现实技术(英文名称&#xff1a;Virtual Reality&#xff0c;缩写为VR)&#xff0c;又称虚拟实境或灵境技术&#xff0c;是20世纪发展起来的一项全新的实用技术。虚拟现实技术囊括计算机、电子信息、仿真技术&#xff0c;其基本实现方式是以计算机技术为主&#xff0c;利用并…

Appium python自动化测试系列之移动自动化测试!

1.1 移动自动化测试现状 因为软件行业越来越发达&#xff0c;用户的接受度也在不断提高&#xff0c;所以对软件质量的要求也随之提高&#xff0c;当然这个也要分行业&#xff0c;但这个还是包含了大部分。因为成本、质量的变化现在对自动化测试的重视度越来越高&#xff0c;在…

【TiDB理论知识09】TiFlash

一 TiFlash架构 二 TiFlash 核心特性 TiFlash 主要有 异步复制、一致性、智能选择、计算加速 等几个核心特性。 1 异步复制 TiFlash 中的副本以特殊角色 (Raft Learner) 进行异步的数据复制&#xff0c;这表示当 TiFlash 节点宕机或者网络高延迟等状况发生时&#xff0c;Ti…

Java一对一聊天

服务端 package 一对一用户;import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Vector;…

[idea]idea连接clickhouse23.6.2.18

一、安装驱动 直接在pom.xml加上那个lz4也是必要的不然会报错 <dependency><groupId>com.clickhouse</groupId><artifactId>clickhouse-jdbc</artifactId><version>0.4.2</version></dependency><dependency><group…

Python函数默认参数设置

在某些情况下&#xff0c;程序需要在定义函数时为一个或多个形参指定默认值&#xff0c;这样在调用函数时就可以省略为该形参传入参数值&#xff0c;而是直接使用该形参的默认值。 为形参指定默认值的语法格式如下&#xff1a; 形参名 默认值 从上面的语法格式可以看出&…

一篇解析context_switch进程切换(针对ARM体系架构)

一. 概述 在最近初学ebpf时&#xff0c;使用到了挂载点finish_task_switch统计内核线程的运行时间&#xff0c;遂进入内核源码对其进行学习分析。 finish_task_switch在context_switch被调用&#xff0c;其功能是完成进程切换的收尾工作&#xff0c;比如地址空间的清理。而co…

理解自我效能感:你的内在动力来源

1. 自我效能感&#xff1a;开启个人潜能的心理动力 想象一下&#xff0c;面对生活的挑战和机遇时&#xff0c;是什么内在力量驱使你去采取行动&#xff0c;或者让你犹豫不决&#xff1f;这种力量&#xff0c;与我们的心理状态紧密相关&#xff0c;其中一个关键因素就是我们的自…

【AIGC】prompt工程从入门到精通

注&#xff1a;本文示例默认“文心大模型3.5”演示&#xff0c;表示为>或w>&#xff08;wenxin)&#xff0c;有时为了对比也用百川2.0展示b>&#xff08;baichuan) 有时候为了模拟错误输出&#xff0c;会用到m>&#xff08;mock)表示&#xff08;因为用的大模型都会…

uView框架的安装与Git管理

参考链接&#xff1a;Http请求 | uView - 多平台快速开发的UI框架 - uni-app UI框架 安装 打开我们项目的cmd进行下载&#xff1a; yarn add uview-ui 首先我们要确定&#xff0c;未下载前的文件目录以及下载后&#xff0c;是多了个文件目录node_modules 下载完成之后我们就…

MTU TCP-MSS(转载)

MTU MTU 最大传输单元&#xff08;Maximum Transmission Unit&#xff0c;MTU&#xff09;用来通知对方所能接受数据服务单元的最大尺寸&#xff0c;说明发送方能够接受的有效载荷大小。 是包或帧的最大长度&#xff0c;一般以字节记。如果MTU过大&#xff0c;在碰到路由器时…