C++ -命名空间-详解

news2024/9/19 8:18:44

博客主页:【夜泉_ly】
本文专栏:【C++】
欢迎点赞👍收藏⭐关注❤️

C++ -命名空间-详解

  • 1.C语言缺点之一 -- 命名冲突
  • 2.命名空间
    • 2.1定义
    • 2.2使用
      • 访问命名空间中的变量
      • 展开命名空间域
      • 指定访问命名空间域
    • 2.3其他功能
  • 3.C++ 标准库中的命名空间
    • 指定展开
  • 4.总结

1.C语言缺点之一 – 命名冲突

先来看看下面这段简单的C语言代码:

#include <stdio.h>
int rand = 0;
int main()
{
	printf("%d\n", rand);
	return 0;
}

运行结果如下:

0

毫无疑问的结果对吧,那如果我再引入这样一个头文件呢:

#include <stdlib.h>

运行结果如下图:
在这里插入图片描述
报错了 ! 原因呢?
在这里插入图片描述
命名冲突 ——如果学过C语言,那应该能知道在<stdlib.h>里面有一个函数,用于生成随机数,而这个函数的名字就是rand,此处,我也定义了同名的变量rand,这就导致了命名冲突。

在C语言中,全局域中命名冲突非常常见,主要有以下两种情况:
1.与库函数冲突:
这就是上面代码报错的原因。
在C语言项目中,可能某天引入了一个库,结果出现了一大堆冲突。
2.开发者相互之间冲突:
在大型项目中,往往都是项目组,这代表不是一个人在写。
那么有没有一种可能,张三写的和李四写的冲突了,但在他们电脑上都能跑。有一天,不同模块合并到一起,结果发现冲突了,这时必然会有一个人要改他的代码。
如果张三、李四都将这个名字在他们的代码里用了几百上千词,那么要修改将是一个极其痛苦的事情。

而C++的祖师爷,下图的本贾尼·斯特劳斯特卢普,同样受够了C语言中的这个缺点,于是在C++中,创造了一个关键字namespace ,用来解决全局域中命名冲突的问题。
在这里插入图片描述

2.命名空间

2.1定义

命名空间可以定义出一个,将其中的内存隔离在这个独立区域,不会与其他区域中的名字冲突:

namespace ly
{
	int rand = 0;
}

在上面的代码中,我定义了一个名为ly的命名空间,里面包含了变量rand。通过这种方式,避免了与标准库rand函数的冲突。

此处,ly是命名空间的名字,这里我取的是我博客名字【夜泉_ly】中的一部分,而一般开发中是用项目名字做命名空间名。

2.2使用

访问命名空间中的变量

在C语言的学习中,可以了解到,同一个域不能定义同名变量,而不同的域可以定义同名变量。
例如,全局作用域和局部作用域:

#include <stdio.h>
int a = 0;//全局域--全局变量
int main()
{
	int a = 1;//局部域--局部变量
	printf("%d\n", a);
	return 0;
}

C语言的域会影响生命周期,也会影响访问,比如上面这段代码的运行结果是1,因为优先访问的是局部变量。
那么有人问了,如果我就想访问全局变量呢?
也是有方法的:

#include <stdio.h>
int a = 0;//全局域--全局变量
int main()
{
	int a = 1;//局部域--局部变量
	printf("%d\n", ::a);
	return 0;
}

这里使用了域作用限定符::,其作用是对左边的域进行访问,此处::左边没有域,即左边为空白,代表对全局域进行访问。
再看下面这种情况:

#include <stdio.h>
int a = 0;//全局域--全局变量
namespace ly
{
	int a = 2;//命名空间域
}
int main()
{
	int a = 1;//局部域--局部变量
	printf("%d\n", a);
	return 0;
}

这里出现了三种域,局部域、全局域、命名空间域,按什么顺序访问?
第一次打印,结果为1,因为默认局部域优先。
再注释掉局部变量a:

//int a = 1;//局部域--局部变量

第二次打印,结果为0,因为局部域未找到指定变量时,会去全局域找。
再注释掉全局变量a:

//int a = 0;//全局域--全局变量

第三。。没有第三次打印了:
在这里插入图片描述
又报错了 ! 原因呢?
在这里插入图片描述
未声明a ——这是因为编译器并不会主动去命名空间域中搜索,所以会报错。
如何访问命名空间域呢?
一般而言,有两种方法:展开命名空间域 OR 指定访问命名空间域。

展开命名空间域

使用using关键字:

using namespace ly;

在一些C++程序开头,常常看见下面这两句代码:

#include <iostream>
using namespace std;

现在可以知道第二句在干什么了:展开了C++标准库的命名空间域。

指定访问命名空间域

printf("%d\n",ly::a);

即在域作用限定符::前加上要访问的命名空间。


现在使用第一个方法,展开命名空间域,来看看下面这段代码会输出什么值?😄

#include <stdio.h>
int a = 0;//全局域--全局变量
namespace ly
{
	int a = 2;//命名空间域
}
using namespace ly;//展开命名空间域
int main()
{
	printf("%d\n", a);
	return 0;
}

什么都输出不了!又报错了:
在这里插入图片描述
其实此处的两个a又冲突了:
展开命名空间域,是将命名空间域中的内容全部暴露到全局域,而同一个域不能定义同名变量,所以编译器会报错。
因此,不要轻易使用using namespace!


回到开头,如果想放心的使用rand作为变量名,可以使用命名空间,并通过指定访问命名空间域的方式访问:

#include <stdio.h>
#include <stdlib.h>
namespace ly
{
	int rand = 0;
}
int main()
{
	printf("%d\n", ly::rand);//打印rand变量的值
	printf("%p\n", rand);//打印rand函数的地址
	return 0;
}

此时可以成功输出结果,如图:
在这里插入图片描述

或许会有人问:为什么不能定义一个局部变量来解决问题?
需注意的是,此处的问题就是定义了一个全局变量,而这个全局变量与库冲突了。因此不能通过定义局部变量解决问题。


2.3其他功能

除了变量,命名空间还可以包含其他内容,例如函数、结构体等。
命名空间甚至可以嵌套使用:

namespace N1
{
	int a = 1;
	namespace N2
	{
		int a = 2;
	}
}

访问时也需多次使用::

printf("%d\n",N1::N2::a);//输出2

通过嵌套命名空间,开发者可以进一步组织和管理代码。


3.C++ 标准库中的命名空间

在学习C语言时,有时也会看到一些C++的代码,这时或许会产生疑问,为什么C++无.h,比如:

#include <iostream.h>

其实,在很早之前,上面这句代码是存在的,在一些老编译器(如VC6.0)上也可以运行,但那时没有命名空间,也不需要展开。

而后来为了与C语言进行区分,并且有了命名空间,C++库、STL等被封进std,这时.h就被去掉了。

现在,标准库通过std命名空间进行管理,在 C++ 的标准库中,所有的库函数和对象都封装在 std 命名空间中。
又由于默认不去命名空间进行搜索,在使用标准库时,可以选择指定访问,例如:

std::cout << "Hello World!" << std::endl;

或者展开空间:

using namespace std;
cout << "Hello World!" << endl;

需注意:这个展开并非展开头文件,因此,展开std不等于不包含头文件!!

在包含了头文件后,在预处理阶段会将其内容展开,而其内容是封在std里的,展开了std,等于告诉编译器可以去这些内容里面进行搜索。
但是,直接展开会有风险,如果自己定义的跟库重名,就会报错,这不就直接回到起点,将C语言的缺点再次包含。
因此,建议在项目中不要展开,而是指定访问;而日常练习中可以展开

而在一个项目中,可能会有百万级的代码量,每次都指定访问太过麻烦,这里就出现了一种新的玩法:

指定展开

例如:

using std::cout;
using std::endl;

只需将常用的展开,不常用的再指定访问,就能大大减少工作量。

4.总结

命名空间是 C++ 中用于解决命名冲突的一个非常重要的工具。
在编写大型项目时,开发者应尽量避免直接展开整个命名空间,而是通过指定访问或部分展开的方式来使用命名空间。
合理使用命名空间不仅能提高代码的可维护性,还能避免命名冲突带来的问题。


希望本篇文章对你有所帮助!并激发你进一步探索编程的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!

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

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

相关文章

华为OD机试 - 二维伞的雨滴效应(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

徒增成本,还是有备无患?说说4G模组SIM双卡切换

初学开发的小伙伴提出疑问&#xff1a; 手机双卡可以理解&#xff0c;人情世故各种缘由…… 物联网设备有必要双卡吗&#xff0c;会不会太浪费&#xff1f; 实际应用中&#xff0c;双卡可不是徒增成本的摆设&#xff0c;而是有备无患的必需。 在使用4G模组双卡功能的场景下&a…

2024年数学建模比赛题目及解题代码

目录 一、引言 1. 1竞赛背景介绍 1.1.1数学建模竞赛概述 1.1.2生产过程决策问题在竞赛中的重要性 1.2 解题前准备 1.2.2 工具与资源准备 1.2.3 心态调整与策略规划 二、问题理解与分析 三、模型构建与求解 3.1 模型选择与设计 3.1.1 根据问题特性选择合适的数学模型类…

每日学习一个数据结构-红黑树

文章目录 什么是红黑树&#xff1f;示意图红黑树的特点红黑树的节点结构插入和删除操作旋转操作重新着色 红黑树的应用 树的构造过程插入新节点自平衡调整策略 示例 查询过程 什么是红黑树&#xff1f; 红黑树&#xff08;Red-Black Tree&#xff09;是一种自平衡的二叉查找树…

关于嵌入式硬件需要了解的基础知识

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于嵌入式硬件基础知识的相关内容&#xff…

TCP: Textual-based Class-aware Prompt tuning for Visual-Language Model

文章汇总 存在的问题 原文&#xff1a;具有图像特定知识的图像条件提示符号在提升类嵌入分布方面的能力较差。 个人理解&#xff1a;单纯把"a photo of {class}"这种提示模版作为输入是不利于text encoder学习的 动机 在可学习的提示和每一类的文本知识之间建立…

2024短剧系统开发,付费短剧小程序app源码教程,分销功能讲解搭建上线

短剧系统技术栈 前端&#xff1a;vue3uniapp 后端&#xff1a; php 数据库&#xff1a;mysql 服务器环境&#xff1a; centos7.6 宝塔 php7.4 MySQL5.7 一、短剧系统功能 短剧用户端&#xff1a; 小程序、抖音小程序、快手小程序、APP、 z付宝小程序 系统用户端详细功能&…

Java创建教程!(*  ̄3)(ε ̄ *)

Java 构造函数 Java面向对象设计 - Java构造函数 构造函数是用于在对象创建后立即初始化对象的代码块。 构造函数的结构看起来类似于一个方法。 声明构造函数 构造函数声明的一般语法是 <Modifiers> <Constructor Name>(<parameters list>) throws <…

安卓14剖析SystemUI的ShadeLogger/LogBuffer日志动态控制输出dumpsy机制

背景&#xff1a; 看SystemUI的锁屏相关代码时候发现SystemUI有一个日志打印相关的方法调用&#xff0c;相比于常规的Log.i直接可以logcat查看方式还是比较新颖。 具体日志打印代码如下&#xff1a; 下面就来介绍一下这个ShadeLogger到底是如何打印的。 分析源码&#xff1…

scanf()函数的介绍及基础用法

目录 scanf&#xff08;&#xff09;函数的介绍及基础用法 一&#xff1a;头文件 二&#xff1a;一般用法 三&#xff1a;返回值 1. 正整数的情况&#xff1a; 2. 0 的情况&#xff1a; 3. EOF的情况&#xff1a; 四&#xff1a;说明 scanf&#xff08;&#xff09;函数…

CCF202006_1

问题描述 试题编号&#xff1a;202006-1试题名称&#xff1a;线性分类器时间限制&#xff1a;1.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 题解&#xff1a; #include<bits/stdc.h>using namespace std; int n, m;struct Node {int x, y;char ch; }node[1010…

9.16日常记录

1.LRU算法 核心思想:LRU算法&#xff08;Least Recently Used&#xff09;是一种常用的缓存淘汰策略&#xff0c;它的核心思想是“如果数据最近被访问过&#xff0c;那么将来被访问的几率也更高”。LRU算法主要用于内存管理和缓存系统。当内存或缓存空间已满&#xff0c;需要腾…

【工具变量】气候适应型试点城市DID(2005-2022年)

数据来源&#xff1a;本数据来源于中国ZF网发布的《关于深化气候适应型城市建设试点的通知》 时间跨度&#xff1a;2005-2022年数据简介&#xff1a;适应型试点城市是指在应对气候变化、提高城市适应能力方面进行先行先试的城市。根据中国ZF网发布的《关于深化气候适应型城市建…

在 Stable Diffusion 1.5 中 Lora, Dreambooth, Textual Inversion的详解指北

Lora, Dreambooth and Textual Inversion 说明 您是否想象过您可爱的宠物与埃菲尔铁塔合影的画面&#xff0c;或者想象过如何生成一张带有您朋友面孔的人工智能图像&#xff1f; 是的&#xff0c;通过稳定扩散技术的微调&#xff0c;这完全是可能的&#xff01; 创建这些场景…

NISP 一级 | 7.2 信息安全风险管理

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 0x01&#xff1a;信息安全风险 信息系统不可能达到绝对安全&#xff0c;但可以通过安全风险&#xff08;以下简称“风险”&#xff09;控制来实现符合个人或单位目标的一定程度的安全。信息安全管…

xxl-job、Quartz、power-job、elastic-job对比选型

一、框架对比 1. Quartz 优点&#xff1a;稳定性和可扩展性好&#xff0c;适用于企业级应用&#xff1b;调度功能丰富&#xff0c;满足多种需求。 缺点&#xff1a;本身不提供原生的分布式支持&#xff0c;需要通过扩展或与其他组件结合来实现分布式任务调度&#xff1b;调度…

树莓派驱动之spi回环测试

开启spi sudo raspi-config选择Interfacing options,选择spi打开 lsmod可以看到spi_bcm2835 短接MISO和MOSI 编写回环代码spitest.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h>…

第六部分:1---进程间通信,匿名管道

目录 进程间通信 进程间通信的目的&#xff1a; 进程间通信的本质&#xff1a; 管道&#xff1a; 管道的定义&#xff1a; 匿名管道 单向通信的管道通路&#xff1a; 进程和文件之间的解耦&#xff1a; 单向管道的读写端回收问题&#xff1a; 管道通信主要实现动态数…

Python VS Golng 谁更胜一筹?

今天我们聊聊Python和Golang这俩到底谁更胜一筹。 这个话题我已经在各种技术论坛上看到无数次了&#xff0c;每次都能引起一波热烈的讨论。作为一个多年写代码的老程序员&#xff0c;今天就站在我的角度&#xff0c;和大家掰扯掰扯这两个语言各自的优缺点。 1. 性能与并发模型…

283. 移动零(快慢指针)

算法分析&#xff1a; 如果数组没有0&#xff0c;快慢指针同步移动&#xff0c;元素会被自己复制&#xff1b;如果有0&#xff0c;快指针找到非零元素&#xff0c;将其复制到慢指针位置最终将剩余位置填充为0。 代码&#xff1a; class Solution {public void moveZeroes(i…