c++ 命名空间

1. 基本概念
 1.1 定义与使用
 1.2 using语句
2. 进阶语法
 2.1 内嵌名字空间
 2.2 扩展性
 2.3 全局作用域
3. 小结

1. 基本概念

名字空间本质上是自定义作用域,由于C++设计的初衷是开发大规模软件,大量的软件库必然会加剧全局符号(变量、函数)的冲突,因此名字空间最基本的作用就是给不同的库和模块拥有自己的独特的作用域,处于不同名字空间中的重名符号相安无事,互不冲突,以此来大大提高编程的便利性。


名字空间

1.1 定义与使用

定义一个名字空间,实际上就是定义一个作用域,在名字空间中可以定义变量、函数等,示例代码如下:

// ns.cpp
// 定义一个名字空间,叫ns
namespace ns
{// 在 ns 中定义变量int a = 1;// 在 ns 中定义函数float f(int x){return x/2;}
}

在以上名字空间 ns 中,定义了一个变量 a 和一个函数 f,但实际上它们的名字是 ns::a 和 ns::f,比如如下示例代码显示了如何正确地引用它们:

// ns.h
namespace ns
{// 对名字空间 ns 中的符号进行声明extern int a;extern float f(int x);
}

// main.cpp
#include "ns.h"int main()
{// 调用名字空间中的符号,使用全称cout << ns::a << endl;cout << ns::f(8) << endl;
}

此处出现了一个新的操作符 ==> :: ,其用法是:

名字空间::某符号
类::某符号

这个双冒号的操作符,称为作用域引用符,很显然,双冒号前面必须是一个作用域,在C++中,除了名字空间是作用域之外,后续会讲到的类也是最常见的作用域。

很显然,将全局变量 a 和函数 f() 放在名字空间中之后,可以极大避免由于不同程序文件或库的重名而引起的冲突。例如,在另外一个名字空间中,出现跟 ns 一样的变量或函数,它们一起使用相安无事:

// another_ns.cpp
namespace another_ns
{int a = 100;
}

// ns.h
namespace ns
{extern int a;extern float f(int x);
}
namespace another_ns
{extern int a;
}

// main.cpp
#include <iostream>
#include "ns.h"int main(void)
{cout << ns::a << endl;         // 输出1cout << another_ns::a << endl; // 输出100
}

另外值得注意的是,名字空间是对变量和函数的定义的作用域规定范围,因此是出现在源文件 *.cpp 中的,而对这些符号的声明,跟原来做法的一样 —— 在对应的头文件中进行声明,只不过在带有名字空间的场合中,头文件的声明语句也同样要包含在名字空间中。

1. 基本概念
 1.1 定义与使用
1.2 using语句
2. 进阶语法
 2.1 内嵌名字空间
 2.2 扩展性
 2.3 全局作用域
3. 小结

1.2 using语句

在上述代码 main.cpp 中,使用了全称 ns::a 和 ns:f 来引用符号,在实际应用中很显然是很不方便的,有没有办法不需要重复写名字空间的名字 ns 也能使用里面定义的符号呢?答案是肯定的,只需要使用 using 语句即可,比如上述源码 main.cpp 可改成如下形式:

// main.cpp
#include "ns.h"
using namespace ns; // 导入名字空间:ns
int main()
{// 调用名字空间 ns 中的符号,不再需要写全名了cout << a << endl;cout << f(8) << endl;
}

对上述代码,需要强调的一点是,using 语句其实有两种形式:

// 形式一:导入整个名字空间中的所有符号
using namespace ns;// 形式二:导入名字空间中的指定符号
using ns::a;
using ns::f;

由于在上述例子中,名字空间 ns 仅仅包含极少量符号,因此不管采用哪种形式的 using 语句都没有什么区别,但如果某个名字空间包含大量符号(比如标准名字空间std),而程序中仅需用到其中的少量符号,那么导入整个名字空间的所有符号的做法也许是不明智的,因为这会使得大量未被使用的符号成为潜在的符号冲突候选人,这种情形被称为名字空间污染,因此,实际编码中我们应在追求便利的同时,尽量避免引入不使用的符号。

「课堂练习1」

有以下代码片段,指出可以改进的地方,并说明原因。

#include <iostream>
using namespace std; // 导入标准名字空间std中的所有符号int main(void)
{cout << "泥猴啊!" << endl;
}

1. 基本概念
 1.1 定义与使用
 1.2 using语句
2. 进阶语法
 2.1 内嵌名字空间
 2.2 扩展性
 2.3 全局作用域
3. 小结

2. 进阶语法

2.1 内嵌名字空间

C++允许嵌套定义名字空间,即一个名字空间内部再出现另一个名字空间,这其实是作用域的常规特性,早在C语言时代就可以有嵌套的作用域的概念,只不过C语言中的作用域都是匿名的,而C++给这些作用域赋予了特定的名字。

// ns.cpp
namespace ns
{int a = 1; // 注意,此处a的全称是 ns::a// 在名字空间中嵌套另一个名字空间namespace nested_ns{int a = 2; // 注意,此处a的全称是 ns::nested_ns::aint x = 100;}
}

声明与使用:

// ns.h
namespace ns
{extern int a;namespace nested_ns{extern int a;extern int x;}
}

// main.cpp
#include "ns.h"int main()
{cout << ns::a << endl;cout << ns::nested_ns::a << endl;cout << ns::nested_ns::x << endl;
}

2.2 扩展性

当程序在多处定义了相同的名字空间时,它们将会融合成一个统一的作用域。如:

// main.cpp
#include <iostream>
#include "ns.h"namespace ns
{// 在名字空间 ns 中增添一个新的符号bint b = 666; 
}using namespace ns;int main(void)
{cout << a << endl; // 访问名字空间 ns 中原有的符号 acout << b << endl; // 访问名字空间 ns 中新增的符号 b
}

2.3 全局作用域

全局作用域是从C语言就开始有的一种作用域,在C++中,有时为了强调某符号的全局特性,或为了避免与导入的名字空间中的重名符号冲突,会在使用全局符号的时候加上 作用域解析符

示例代码:

int global = 100;
int main()
{int global = 200;// 重名的标识符,外层的作用域会被内层的掩盖cout <<   global << endl; // 输出200// 使用双冒号引用全局作用域中的标识符cout << ::global << endl; // 输出100
}

  1. 全局作用域的名字空间是匿名的,引用全局作用域符号只需加 :: 即可。
  2. 名字空间的本质就是作用域,遵守C语言关于作用域的基本原则,如内层作用域重名符号会掩盖外层作用域的重名符号。

1. 基本概念
 1.1 定义与使用
 1.2 using语句
2. 进阶语法
 2.1 内嵌名字空间
 2.2 扩展性
 2.3 全局作用域
3. 小结

3. 小结

  • 自定义名字空间,实际上是将原来C语言中的全局作用域做了更加细致的规划,在原先的全局作用域中,人为地将某个区域内的符号(变量、对象、函数)命个名圈起来,避免与全局作用域中的其余符号冲突。

  • 如果不可避免地要引入不同的名字空间(比如space1和space2),并且不同的名字空间中恰巧有重名的符号(比如var),那么引用方只需将符号带上其所属的名字空间的名称即可(比如space1::var 和 space2::var)。这大大拓展了大型程序对不同函数库符号引入的灵活性,大大缓解了符号的冲突的可能。

  • 引入名字空间的初衷,是解决大型软件中的各个不同产商提供的第三方库的名字冲突问题,这是从C语言到C++的一个重大的改变。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot +Vue3 简单的前后端交互

前端&#xff1a;Vue3 创建项目&#xff1a; npm create vuelatest > cd <your-project-name> > npm install > npm run dev 项目结构图如下&#xff1a; 1、查看入口文件内容&#xff1a;main.js 代码如下&#xff1a; import ./assets/main.css impor…

Java接口详解

接口 接口的概念 在现实生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&#xff1a;笔记本上的USB口&#xff0c;电源插座等。 电脑的USB口上&#xff0c;可以插&#xff1a;U盘&#xff0c;鼠标&#xff0c;键盘等所有符合USB协议的设备 电源插座插孔上&#xff0c;…

IDEA常用插件之代码规范检查

Alibaba Java Coding Guidelines 安装 使用 手动扫描 这里扫描可以扫描某一个类、某一个包、整个项目都支持 扫描结果 实时扫描 开启实时扫描在代码编写过程中也会实时提醒

最新AI系统ChatGPT程序源码+搭建部署教程/支持GPT4/支持ai绘画/H5端/完整知识库

一、AI系统 如何搭建部署AI创作ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01; SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 程序核心功能&#xff1a; 程序已支持ChatGPT3.5/4.0提问、AI绘画、Midjourney绘画&…

【Hello Network】数据链路层协议

本篇博客简介&#xff1a;介绍数据链路层的各协议 数据链路层 以太网协议认识以太网协议以太网帧格式局域网通信原理再理解 MTU认识MTUMTU对IP协议的影响MTU对UDP协议的影响MTU对于TCP协议的影响如何查看ip地址 mac地址 以及mtu ARP协议ARP协议的作用ARP协议在哪里ARP的工作过程…

stm32单片机/51单片机蜂鸣器不响(proteus模拟)

蜂鸣器不发生原因就1个&#xff1a;电压不够 所以需要提高蜂鸣器2端的电压&#xff1a;可以采用的方法有&#xff1a; 1提高蜂鸣器电阻&#xff0c;这样根据分压原理&#xff0c;可以提升蜂鸣器2段电压 2更改蜂鸣器的工作电压为更小的值&#xff0c;这个可以通过在proteus内…

LeetCode 42题:接雨水

题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1,…

水经微图网页版基础名词

水经微图网页版&#xff0c;可轻松将关注的地点制作成您的个人地图。 您可以在任意位置添加标注点或绘制地图&#xff0c;查找地点并将其保存到您的地图中&#xff0c;或导入地图数据迅速制作地图并保存&#xff0c;您还可以运用图标和颜色展示个性风采&#xff0c;从而可让每…

关于slot-scope已经废弃的问题

说起来啊&#xff0c;这个问题啊&#xff0c;我之前一直没关注&#xff0c;还是webstorm给我的警告。 因为使用了element-ui的组件库&#xff0c;所以在使用组件的时候往往就cv大法了&#xff0c;直到今天用webstorm写代码是&#xff0c;提示了如下的错误 我这一看&#xff0c…

C++Qt堆叠窗体的使用案例

本博文源于笔者最近学习的Qt&#xff0c;内容讲解堆叠窗体QStackedWidget案例&#xff0c;效果是选择左侧列表框中不同的选项时&#xff0c;右侧显示所选的不同的窗体。 案例效果 案例书写过程 控件都是动态创建的&#xff0c;因此.h文件需要创建控件&#xff0c;.cpp书写业务…

js判断类型:typeof Object.prototype.toString instanceof constructor有什么区别?一文讲清楚

相信很多小伙伴在使用js的过程中&#xff0c;经常会需要对js的数据类型进行判断&#xff0c;而js中可以对数据类型进行判断的方法有很多种&#xff0c;最常见的有typeof、Object.prototype.toString、instanceof、constructor这四种&#xff0c;那么他们有什么区别呢&#xff1…

.NET应用UI组件DevExpress XAF v23.1 - 全新的日程模块

DevExpress XAF是一款强大的现代应用程序框架&#xff0c;允许同时开发ASP.NET和WinForms。DevExpress XAF采用模块化设计&#xff0c;开发人员可以选择内建模块&#xff0c;也可以自行创建&#xff0c;从而以更快的速度和比开发人员当前更强有力的方式创建应用程序。 在新版中…

2023国赛数学建模思路 - 案例:粒子群算法

文章目录 1 什么是粒子群算法&#xff1f;2 举个例子3 还是一个例子算法流程算法实现建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 什么是粒子群算法&#xff1f; 粒子群算法&#xff08;Pa…

业务系统架构实践总结

我从2015年起至今2022年&#xff0c;在业务平台&#xff08;结算、订购、资金&#xff09;、集团财务平台&#xff08;应收应付、账务核算、财资、财务分析、预算&#xff09;、本地生活财务平台&#xff08;发票、结算、预算、核算、稽核&#xff09;所经历的业务系统研发实践…

网络安全---Ring3下动态链接库.so函数劫持

一、动态链接库劫持原理 1.1、原理 Unix操作系统中&#xff0c;程序运行时会按照一定的规则顺序去查找依赖的动态链接库&#xff0c;当查找到指定的so文件时&#xff0c;动态链接器(/lib/ld-linux.so.X)会将程序所依赖的共享对象进行装载和初始化&#xff0c;而为什么可以使用…

Git学习笔记

Git学习笔记 文章目录 Git学习笔记一、版本控制二、Linux基础命令三、Git的环境配置四、Git的基本理论&#xff08;核心&#xff09;五、Git项目的搭建六、Git文件操作七、使用码云八、IDEA集成git九、Git分支 一、版本控制 什么是版本控制 版本控制&#xff08;Revision contr…

Linux线程 --- 生产者消费者模型(C语言)

在学习完线程相关的概念之后&#xff0c;本节来认识一下Linux多线程相关的一个重要模型----“ 生产者消费者模型” 本文参考&#xff1a; Linux多线程生产者与消费者_红娃子的博客-CSDN博客 Linux多线程——生产者消费者模型_linux多线程生产者与消费者_两片空白的博客-CSDN博客…

RedisTemplate和StringRedisTemplate的区别、对比

学习 Jedis、RedisTemplate、StringRedisTemplate之间的比较 博客中提到&#xff1a;一. Jedis是Redis官方推荐的面向Java的操作Redis的客户端。 二. RedisTemplate,StringRedisTemplate是SpringDataRedis中对JedisApi的高度封装。SpringDataRedis相对于Jedis来说可以方便地更…

想解锁禁用的iPhone?除了可以使用电脑之外,这里还有不需要电脑的方法!

多次输入错误的密码后,iPhone将显示“iPhone已禁用”。这种情况看起来很棘手,因为你现在不能用iPhone做任何事情。对于这种情况,我们提供了几种有效的方法来帮助你在最棘手的问题中解锁禁用的iPhone。你可以选择使用或不使用电脑来解锁禁用的iPhone。 一、为什么你的iPhone…

Mysql数据库管理

一、数据库基本概念 数据 使用一些介质进行存储&#xff0c;例如文字存在文档中 数据库可以完成数据持久化保存快速提取 那么想要实现以上功能&#xff0c;需要编写一系列的规则--》SQL语句 SQL语句 按功能分类: 增删改查 数据库类型&#xff1a;关系型数据库、非关系型数据库…