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;         // 输出1
    cout << 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::a
        int 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 中增添一个新的符号b
    int b = 666; 
}

using namespace ns;

int main(void)
{
    cout << a << endl; // 访问名字空间 ns 中原有的符号 a
    cout << 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++的一个重大的改变。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Word中对象方法(Methods)的理解及示例(上)

【分享成果&#xff0c;随喜正能量】奋斗没有终点,任何时候都是一个起点&#xff0c;沉潜是为了蓄势待发&#xff0c;沉潜是为了等待因缘。鲸豚沉潜于大海&#xff0c;幽兰深藏于山谷&#xff0c;能够经得起沉潜的人&#xff0c;才会有更高的成就。正如一年的树木只能当柴烧&am…

PPPoE vs 静态:网络中的最佳选择

在企业网络中&#xff0c;选择适合的网络连接方式对于网络性能和安全至关重要。今天我将和大家分享关于PPPoE和静态IP地址的知识&#xff0c;探讨它们在企业网络中的优劣和最佳选择。本文将为您提供详细的分析和解决方案&#xff0c;帮助您在选择网络连接方式时做出明智的决策。…

Jmeter常用线程组设置策略

一、前言 ​ 在JMeter压力测试中&#xff0c;我们时常见到的几个场景有&#xff1a;单场景基准测试、单场景并发测试、单场景容量测试、混合场景容量测试、混合场景并发测试以及混合场景稳定性测试 在本篇文章中&#xff0c;我们会用到一些插件&#xff0c;在这边先给大家列出&…

小兔鲜儿 - 推荐模块

目录 动态获取数据 静态结构 获取页面参数​ 获取数据​ 类型声明 热门推荐 – 渲染页面和Tab交互 热门推荐 – 分页加载 热门推荐 – 分页条件 type 和 interface 的区别 type 和 interface 的相似之处 type 的特点和用途 interface 的特点和用途 何时使用 type…

数据结构:直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序,计数排序(C实现)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》 文章目录 前言一、插入排序1.直接插入排序2.希尔排序 二、选择排序1. 选择排序2.堆排序 三、交换排序1.冒泡排序2.快速排序(递归)a.hoare版(PartSort1)b.挖坑法(PartSort2)c.前后指针法(PartSort…

【云驻共创】华为云之手把手教你搭建IoT物联网应用充电桩实时监控大屏

文章目录 前言1.什么是充电桩2.什么是IOT3.什么是端、边、云、应用协同4.什么是Astro轻应用 一、玩转lOT动态实时大屏&#xff08;线下实际操作&#xff09;1.Astro轻应用说明1.1 场景说明1.2 资费说明1.3 整体流程 2.操作步骤2.1 开通设备接入服务2.2 创建产品2.3 注册设备2.4…

vue页面转pdf后分页时文字被横向割裂

效果 预期效果 //避免分页被截断async outPutPdfFn (id, title) {const _t this;const A4_WIDTH 592.28;const A4_HEIGHT 841.89;// dom的id。let target document.getElementById(pdf);let pageHeight target.scrollWidth / A4_WIDTH * A4_HEIGHT;// 获取分割dom&#xf…

static相关知识点详解

文章目录 一. 修饰成员变量二. 修饰成员方法三. 修饰代码块四. 修饰类 一. 修饰成员变量 static 修饰的成员变量&#xff0c;称为静态成员变量&#xff0c;该变量不属于某个具体的对象&#xff0c;是所有对象所共享的。 public class Student {private String name;private sta…

MySQL-Centos下MySQL5.7安装教程

MySQL安装教程 一&#xff0c;卸载MySQL二&#xff0c;安装MySQL三&#xff0c;mysql登录四&#xff0c;修改配置文件 一&#xff0c;卸载MySQL 1.如果你的机器上mysqld服务器还在运行&#xff0c;那么第一步就是要停掉服务。 systemctl stop mysqld;2.查看系统中安装的关于m…

vim 常见操作

Vim 工作模式 1、vim 三种基本的工作模式 vim有三种基本的工作模式&#xff0c;分别为&#xff1a;命令模式、末行模式、编辑模式。关于这三种工作模式的介绍&#xff0c;请见下文。 1.1、命令模式 使用vim打开文件之后&#xff0c;首先进入命令模式&#xff0c;它是vim编辑…

RISC-V公测平台发布· CoreMark测试报告

一. CoreMark简介 CoreMark是一款用于评估CPU性能的基准测试程序&#xff0c;它包含了多种不同的计算任务&#xff0c;包括浮点数、整数、缓存、内存等方面的测试。CoreMark的测试结果通常被用来作为CPU性能的参考&#xff0c;它可以帮助开发人员和系统管理员评估不同处理器和…

iOS 如何对整张图分别局部磨砂,并完全贴合

官方磨砂方式 - (UIVisualEffectView *)effectView{if(!_effectView){UIBlurEffect *blur [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];_effectView [[UIVisualEffectView alloc] initWithEffect:blur];}return _effectView; }使用这种方式对一张图的上半部分和…

数学建模大全及优缺点解读

分类模型 1、距离聚类&#xff08;系统聚类&#xff09;&#xff08;常用&#xff0c;需掌握&#xff09; 优点&#xff1a; ①将一批样本数据按照他们在性质上的亲密程度在没有先验知识的情况下自动进行分类 ②是一种探索性的分析方法&#xff0c;分类结果不一定相同 例如&am…

住宅IP:解锁更快速、稳定的互联网,你准备好了吗?

随着互联网的广泛普及&#xff0c;我们对网络的需求也越来越高。无论是工作、学习还是娱乐&#xff0c;我们都希望能够享受到更快速、稳定的互联网连接。而在实现这一目标的过程中&#xff0c;住宅IP正逐渐崭露头角&#xff0c;成为了一种备受关注的解决方案。那么&#xff0c;…

用户端Web自动化测试-L2

目录&#xff1a; 高级定位-css高级定位-xpath显式等待高级使用高级控件交互方法网页 frame 与多窗口处理文件上传&#xff0c;弹框处理自动化关键数据记录电子商务产品实战 1.高级定位-css css 选择器概念 css 选择器有自己的语法规则和表达式css 定位通常分为绝对定位和相…

Java IO流(四)Netty理论[模型|核心组件]

概述 Netty是由JBOSS提供的一个Java开源框架,可从Github获取独立项目Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端(摘录官网)Netty所谓的异步是针对用户使用Channel进行IO操作,会立即返回ChannelFuture。但IO操作的任务是提…

开源容灾备份软件,开源cdp备份软件

数据的安全性和完整性面临着硬件问题、黑客攻击、人为错误等各种威胁。在这种环境下&#xff0c;开源容灾备份软件应运而生&#xff0c;通过提供自动数据备份和恢复&#xff0c;有效地保证了公司的数据安全。 一、开源容灾备份软件的定义和作用 开源容灾备份软件是一种基于开源…

SqlServer2019—解决SQL Server 无法连接127.0.0.1的问题

1、打开SQL Server 2019配置管理器 2、SQL Servere 网络配置(启用 Named Pipes 和 TCP/IP) 3、修改TCP/IP协议(右键选择属性—IP地址)&#xff0c;具体如下图所示&#xff1a; 4、重启SQL Server服务

漏洞挖掘和漏洞利用技术:讨论漏洞发现、利用和修复,深入研究不同类型漏洞的技术细节

章节一&#xff1a;引言 在当今数字化时代&#xff0c;计算机技术的迅猛发展为我们的生活带来了无数便利&#xff0c;然而也伴随着各种安全威胁。恶意黑客利用漏洞进行攻击已成为一种常见现象。本文将深入探讨漏洞挖掘和漏洞利用技术&#xff0c;以及如何修复这些漏洞&#xf…

智慧充电桩物联网方案架构

智慧充电桩物联网采用“云-管-边-端”的边缘计算物联网架构&#xff0c;融合5G、AI、Wi-Fi 6等技术&#xff0c;实现充电基础设施由数字化向智能化演进。智慧充电桩物联网方案架构设计&#xff0c;如下图所示&#xff1a; 云端&#xff1a; 物联网平台具备广泛协议的南向接入…