编程视界:C++命名空间

目录

命名空间

为什么要使用命名空间

什么是命名空间

命名空间的使用方式

关键点总结

命名空间的嵌套使用

匿名命名空间

跨模块调用问题

命名空间可以多次定义

总结


首先从C++的hello,world程序入手,来认识一下C++语言

#include <iostream>
using namespace std;int main(int argc, char * argv[]){cout << "hello,world" << endl;return 0;
}>

(1)iostream是C++的头文件,为什么没有后缀?—— 模板阶段再作讲解

(2)using namespace std是什么含义?—— 命名空间的使用

(3) cout << "hello,world" << endl; 实现了输出hello,world的功能,如何理解这行代码?—— cout的使用

命名空间

为什么要使用命名空间

一个大型的工程往往是由若干个人独立完成的,不同的人分别完成不同的部分,最后再组合成一个完整的程序。由于各个头文件是由不同的人设计的,有可能在不同的头文件中用了相同的名字来命名所定义的类或函数,这样在程序中就会出现名字冲突。不仅如此,有可能我们自己定义的名字会与C++库中的名字发生冲突。

名字冲突就是在同一个作用域中有两个或多个同名的实体,为了解决命名冲突 ,C++中引入了命名空间,所谓命名空间就是一个可以由用户自己定义的作用域,在不同的作用域中可以定义相同名字的变量,互不干扰,系统能够区分它们。

C语言中避免名字冲突,只能进行起名约定

int hw_cpp_tom_num = 100;
int wd_cpp_bob_num = 200;

什么是命名空间

命名空间又称为名字空间,是程序员命名的内存区域,程序员根据需要指定一些有名字的空间域,把一些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。通俗的说,每个名字空间都是一个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效。名字空间对全局实体加以域的限制,从而合理的解决命名冲突。

C++中定义命名空间的基本格式如下:

namespace wd
{
int val1 = 0;
char val2;
}// end of namespace wd

在声明一个命名空间时,大括号内不仅可以存放变量,还可以存放以下类型:

变量、常量、函数、结构体、引用、类、对象、模板、命名空间等,它们都称为实体

(1)请尝试定义命名空间,并在命名空间中定义实体。

(2)命名空间中的实体如何使用呢?

命名空间的使用方式

命名空间一共有三种使用方式,分别是using编译指令、作用域限定符、using声明机制。

  1. 作用域限定符

    每次要使用某个命名空间中的实体时,都直接加上作用域限定符::,例如:

    namespace wd
    {
    int number = 10;
    void display()
    {//cout,endl都是std空间中的实体,所以都加上'std::'命名空间std::cout << "wd::display()" << std::endl;
    }
    }//end of namespace wdint main(void)
    {std::cout << "wd::number = " << wd::number << endl;wd::display();return 0;
    }

    好处:准确,只要命名空间中确实有这个实体,就能够准确调用(访问)

    坏处:繁琐

  2. using编译指令

    我们接触的第一个C++程序基本上都是这样的,其中std代表的是标准命名空间。

    #include <iostream>
    using namespace std; //using编译指令int main(int argc, char * argv[]){cout << "hello,world" << endl;return 0;
    }

    其中第二行就使用了using编译指令。如果一个名称空间中有多个实体,使用using编译指令,就会把该空间中的所有实体一次性引入到程序之中;对于初学者来说,如果对一个命名空间中的实体并不熟悉时,直接使用这种方式,有可能还是会造成名字冲突的问题,而且出现错误之后,还不好查找错误的原因,比如下面的程序就会报错,当然该错误是人为造成的。

    #include <iostream>
    using namespace std;
    double cout()
    {
    return 1.1;
    }
    int main(void)
    {
    cout();
    return 0;
    }

    image-20240305113638435

  3. using声明机制

using声明机制的作用域是从using语句开始,到using所在的作用域结束。要注意,在同一作用域内用using声明的不同的命名空间的成员不能有同名的成员,否则会发生重定义。

作用域示例

namespace A {void foo() {}int x = 10;
}void func1() {using A::foo; // 作用域开始foo();        // 正确:调用 A::foo()
} // 作用域结束(到 func1 末尾)void func2() {// foo();     // 错误:此处无法使用 A::foo
}

重定义示例

namespace B {void foo() {}  // 与 A::foo 同名但实现不同int x = 20;    // 与 A::x 同名
}// 全局作用域中的 using 声明
using A::x;     // 引入 A::x
using B::x;     // 错误:重定义!x 已存在(来自 A)int main() {// x = 30;  // 若单独使用一个 using 声明,此处可访问return 0;
}

合法作用域示例

void safe_func1() {using A::foo;foo();  // 调用 A::foo
}void safe_func2() {using B::foo;foo();  // 调用 B::foo(不同作用域,无冲突)
}
关键点总结
  1. 作用域限定using 声明的作用域从声明处开始,到当前代码块({})结束

  2. 冲突规则:同一作用域内不允许通过 using 引入同名标识符

  3. 隔离方案:通过函数/代码块划分作用域可避免冲突

  4. using namespace 区别using 声明精确引入单个标识符,using namespace 会污染当前作用域的所有标识符

实际开发中建议:

  • 优先在函数内局部使用 using 声明

  • 避免在头文件的全局作用域使用 using

  • 对频繁使用的标识符,使用 namespace alias(如 namespace fs = std::filesystem;

#include <iostream>
using std::cout;
using std::endl;
namespace wd
{
int number = 10;
void display()
{
cout << "wd::display()" << endl;
}
}//end of namespace wd
using wd::number;
using wd::display;
int main(void)
{cout << "wd::number = " << number << endl;wd::display();return 0;
}

在这三种方式之中,我们推荐使用的就是第三种,需要哪个实体的时候就引入到程序中,不需要的实体就不引入,尽可能减小犯错误的概率。

image-20240305113925045

命名空间的嵌套使用

类似于文件夹下还可以建立文件夹,命名空间中还可以定义命名空间。那么内层命名空间中的实体如何访问呢?尝试一下

image-20240305114217487

image-20240305114537247

匿名命名空间

命名空间还可以不定义名字,不定义名字的命名空间称为匿名命名空间(简称匿名空间),其定义方式如下:

namespace {
int val1 = 10;
void func();
}//end of anonymous namespace

image-20240305115202613

使用匿名空间中实体时,可以直接使用,也可以加上作用域限定符(没有空间名),但是如果匿名空间中定义了和全局位置中同名的实体,会有冲突,即使使用::作用域限定符也无法访问到匿名空间中重名的实体,只能访问到全局的实体。

在C++代码中可以直接使用一些C语言的函数,就是通过匿名空间实现(体现了C++对C的兼容性),在本文件使用匿名命名空间的实体时不必用命名空间限定。

image-20240305120025058

image-20240305120642759

printf本身可以直接用,和C语言中的效果一致。但是经过匿名空间改写后,效果不一样了 —— 不要随意改写

匿名空间注意事项:

(1)匿名空间不要定义与全局空间中同名的实体;

(2)匿名空间中支持改写兼容C语言的函数,但是最好不要改写;

(3)匿名空间中的实体不能跨模块调用。

补充:匿名空间和有名空间(具名空间)统称为命名空间(名称空间)。

跨模块调用问题

一个.c/.cc/*.cpp的文件可以称为一个模块。

(1)全局变量和函数是可以跨模块调用的

externA.cc

image-20240305144421267

externB.cc

image-20240305144326193

对externA.cc和externB.cc联合编译,实现跨模块调用

(2)有名命名空间中的实体可以跨模块调用

image-20240305181047048

命名空间中的实体跨模块调用时,要在新的源文件中再次定义同名的命名空间,进行联合编译时,这两次定义被认为是同一个命名空间。

使用规则:如果要同时从全局位置和命名空间中外部引入实体,要么让它们不要重名,要么在使用时采取作用域限定的方式。

using wd2 :: num 放在test2外面就发生冲突,使用using namespace wd2 也会发生冲突,看似不在一个作用域也会冲突,所以就用上面的解决办法。

(3)静态变量和函数只能在本模块内部使用

image-20240305151609213

(4)匿名空间的实体只能在本模块内部使用

匿名空间中的实体只能在本文件的作用域内有效,它的作用域是从匿名命名空间声明开始到本文件结束。

image-20240305153745838

补充:extern外部引入的方式适合管理较小的代码组织,用什么就引入什么,但是如果跨模块调用的关系不清晰,很容易出错;

include头文件的方式在代码组织上更清晰,但是会一次引入全部内容,相较而言效率比较低。

命名空间可以多次定义

函数可以声明多次,但是只能定义一次;命名空间可以多次定义。

image-20240305152144711

在同一个源文件中可以多次定义同名的命名空间,被认为是同一个命名空间,所以不能进行重复定义。

image-20240305152606533

在命名空间中可以声明实体、定义实体,但是不能使用实体。使用命名空间中的实体一定在命名空间之外,可以理解为命名空间只是用来存放实体。

总结

命名空间的作用:

  1. 避免命名冲突:命名空间提供了一种将全局作用域划分成更小的作用域的机制,用于避免不同的代码中可能发生的命名冲突问题;

  2. 组织代码:将相关的实体放到同一个命名空间;

  3. 版本控制:不同版本的代码放到不同的命名空间中;

    总之,需要用到代码分隔的情况就可以考虑使用命名空间。

还有一个隐藏的好处:声明主权。

下面引用当前流行的命名空间使用指导原则:

  1. 提倡在已命名的名称空间中定义变量,而不是直接定义外部全局变量或者静态全局变量。

  2. 如果开发了一个函数库或者类库,提倡将其放在一个命名空间中。

  3. 对于using 声明,首先将其作用域设置为局部而不是全局。

  4. 不要在头文件中使用using编译指令,这样,使得可用名称变得模糊,容易出现二义性。

  5. 包含头文件的顺序可能会影响程序的行为,如果非要使用using编译指令,建议放在所有#include预编译指令后。

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

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

相关文章

Redux 和 MobX 高频面试题

Redux 和 MobX 是 React 生态中的两大状态管理方案&#xff0c;在面试中常涉及 原理、使用方式、对比、最佳实践 等方面。以下是 高频面试题 详细答案&#xff0c;助你轻松应对面试&#xff01;&#x1f680; &#x1f525; Redux 部分 1. Redux 是什么&#xff1f;为什么需要…

Excel 保护工作簿:它能解决哪些问题?如何正确使用?

在日常办公中&#xff0c;Excel 表格常常涉及多人协作、重要数据保护&#xff0c;甚至是避免误操作的情况。这时候&#xff0c;“保护工作簿”功能就能派上用场。它能有效防止他人修改表结构、删除工作表&#xff0c;甚至可以设置密码&#xff0c;确保数据的完整性和安全性。今…

Android Retrofit 框架注解定义与解析模块深度剖析(一)

一、引言 在现代 Android 和 Java 开发中&#xff0c;网络请求是不可或缺的一部分。Retrofit 作为 Square 公司开源的一款强大的类型安全的 HTTP 客户端&#xff0c;凭借其简洁易用的 API 和高效的性能&#xff0c;在开发者社区中广受欢迎。Retrofit 的核心特性之一便是通过注…

C# Enumerable类 之 数据分组

总目录 前言 在 C# 中&#xff0c;System.Linq.Enumerable 类是 LINQ&#xff08;Language Integrated Query&#xff09;的核心组成部分&#xff0c;它提供了一系列静态方法&#xff0c;用于操作实现了 IEnumerable 接口的集合。通过这些方法&#xff0c;我们可以轻松地对集合…

推理模型对SQL理解能力的评测:DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet

引言 随着大型语言模型&#xff08;LLMs&#xff09;在技术领域的应用日益广泛&#xff0c;评估这些模型在特定技术任务上的能力变得越来越重要。本研究聚焦于四款领先的推理模型——DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet在SQL理解与分析方面的能力&#xff0c;…

IDEA接入阿里云百炼中免费的通义千问[2025版]

安装deepseek 上一篇文章IDEA安装deepseek最新教程2025中说明了怎么用idea安装codeGPT插件&#xff0c;并接入DeepSeek&#xff0c;无奈接入的官方api已经不能使用了&#xff0c;所以我们尝试从其他地方接入 阿里云百炼https://bailian.console.aliyun.com/ 阿里云百炼‌是阿…

实施一套先进的智能摄像头服务系统。

一、项目背景 随着物联网、人工智能和大数据技术的飞速发展&#xff0c;智能摄像头已成为家庭、企业以及公共安全领域的重要设备。其便捷、高效、智能的特点&#xff0c;使得市场需求日益增长。为了满足用户对智能监控的多样化需求&#xff0c;提供更加全面、可靠的监控服务&a…

linux自启动服务

在Linux环境中&#xff0c;systemd是一个系统和服务管理器&#xff0c;它为每个服务使用.service文件进行配置。systemctl是用于控制系统服务的主要工具。本文将详细介绍如何使用systemctl来管理vsftpd服务&#xff0c;以及如何设置服务自启动。 使用Systemd设置自启动服务 创…

010-Catch2

Catch2 一、框架简介 Catch2 是一个基于 C 的现代化单元测试框架&#xff0c;支持 TDD&#xff08;测试驱动开发&#xff09;和 BDD&#xff08;行为驱动开发&#xff09;模式。其核心优势在于&#xff1a; 单头文件设计&#xff1a;v2.x 版本仅需包含 catch.hpp 即可使用自然…

数字人分身开发指南:从概念到实战

一、什么是数字人分身&#xff1f; 想象一下&#xff0c;在电脑或手机屏幕里&#xff0c;一个能跟你聊天、回答问题&#xff0c;甚至还能做表情的虚拟角色。这就是数字人分身&#xff0c;它用上了人工智能技术&#xff0c;让机器也能像人一样交流。无论是在线客服、网络主播还…

Pixelmator Pro for Mac 专业图像处理软件【媲美PS的修图】

介绍 Pixelmator Pro&#xff0c;是一款非常强大、美观且易于使用的图像编辑器&#xff0c;专为 Mac 设计。采用单窗口界面、基于机器学习的智能图像编辑、自动水平检测&#xff0c;智能快速选择及更好的修复工具等功能优点。许多非破坏性的专业编辑工具可让您进行最佳的照片处…

LiveGBS流媒体平台GB/T28181常见问题-视频流安全控制HTTP接口鉴权勾选流地址鉴权后401Unauthorized如何播放调用接口流地址校验

LiveGBS流媒体平台GB/T28181常见问题频流安全控制HTTP接口鉴权勾选流地址鉴权后401Unauthorized如何播放调用接口流地址校验&#xff1f; 1、安全控制1.1、HTTP接口鉴权1.2、流地址鉴权 2、401 Unauthorized2.1、携带token调用接口2.1.1、获取鉴权token2.1.2、调用其它接口2.1.…

C++设计模式-抽象工厂模式:从原理、适用场景、使用方法,常见问题和解决方案深度解析

一、模式基本概念 1.1 定义与核心思想 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是创建型设计模式的集大成者&#xff0c;它通过提供统一的接口来创建多个相互关联或依赖的对象族&#xff0c;而无需指定具体类。其核心思想体现在两个维度&#xff1a; …

【prompt实战】知乎问题解答专家

本文原创作者&#xff1a;姚瑞南 AI-agent 大模型运营专家&#xff0c;先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗&#xff1b;多年人工智能行业智能产品运营及大模型落地经验&#xff0c;拥有AI外呼方向国家专利与PMP项目管理证书。&#xff08;转载需经授权&am…

数据结构第八节:红黑树(初阶)

【本节要点】 红黑树概念红黑树性质红黑树结点定义红黑树结构红黑树插入操作的分析 一、红黑树的概念与性质 1.1 红黑树的概念 红黑树 &#xff0c;是一种 二叉搜索树 &#xff0c;但 在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是 Red和 Black 。 通过对 任何…

Spring Boot3.3.X整合Mybatis-Plus

前提说明&#xff1a; 项目的springboot版本为&#xff1a;3.3.2 需要整合的mybatis-plus版本&#xff1a;3.5.7 废话不多说&#xff0c;开始造吧 1.准备好数据库和表 2.配置全局文件application.properties或者是application.yml&#xff08;配置mapper的映射文件路径&am…

可视化图解算法:链表指定区间反转

1. 题目 描述 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例1 输入&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输…

✨SQL-递归CTE

&#x1f4d6; SQL魔法课堂&#xff1a;CTE「时间折叠术」全解 &#x1f3a9; 第一章&#xff1a;什么是CTE&#xff1f; CTE&#xff08;Common Table Expression&#xff09; 就像 SQL 里的「临时笔记本」&#x1f4d2;&#xff1a; WITH 临时笔记本 AS ( SELECT ... FRO…

Cursor 新手入门使用教程

一、Cursor 是什么&#xff1f; Cursor 是一个集成了 GPT-4、Claude 3.5 等先进 LLM&#xff08;大语言模型&#xff09;的类 VSCode 编译器&#xff0c;可以理解为在 VSCode 中集成了 AI 辅助编程助手。从界面布局来看&#xff0c;Cursor 与 VSCode 基本一致&#xff0c;且使…

如何在Spring Boot中配置和使用MyBatis-Plus

在当今的Java开发中&#xff0c;Spring Boot已经成为了一个非常流行的框架&#xff0c;而MyBatis-Plus则是一个强大的ORM框架&#xff0c;为开发人员提供了更简便的数据库操作方式。很多开发者都在使用Spring Boot和MyBatis-Plus的组合来快速构建高效的应用。今天就来聊聊如何在…