解构C++高级命名空间:构建空间作用域·控制兼容

**前引:**C++作为C语言的继承者,也是其掘墓人。在编程语言的演化长河中,C++始终游走在【兼容】与【革新】的路上。C程序员眼中(高效直接)的全局函数,对于C++开发者来说是【命名空间污染的炸弹】,如果C++未发明命名空间,今天的Linux内核是否还会选择extern"C"包裹所有的C++代码。下面我们来看看命名空间如何构建模块化生态~

目录

命名空间介绍

如何声明命名空间

基础命名空间

嵌套命名空间

匿名命名空间

如何使用命名空间

完全限定访问

[using 声明(局部引入)](#using 声明(局部引入))

[using namespace指令(全局引入)](#using namespace指令(全局引入))

回顾整理

标准库的命名空间

[头文件与 std 的关系](#头文件与 std 的关系)

[cout 、cin、 endl 的深度解析](#cout 、cin、 endl 的深度解析)

[(1)std :: cout 表示标准输出流](#(1)std :: cout 表示标准输出流)

[(2)std :: endl 流操纵符](#(2)std :: endl 流操纵符)

[(3)std :: cin 标准输入流](#(3)std :: cin 标准输入流)

常见错误

总结


命名空间介绍

命名是(Namespace)是C++提供的一种代码隔离机制,用于将全局作用域划分为逻辑独立的区域,避免不同模块或库中的同名标识符(变量、函数、类等)发生冲突,一个命名空间就定义了一个新的作用域

例1:A程序员与B程序员现在分模块完成某个工程,A程序员定义了变量tmp ,B程序员也定义了 变量tmp,最后二者模块合并时,可能导致重定义变量报错

例2:C++库中可能定义了某个关键字,但是程序员也可能定义了某个与库中一模一样的变量,这 就无法通过编译

如何声明命名空间

命名空间应该在全局定义,而不是局部

基础命名空间

命名空间使用关键字 namespace 定义,后面跟上命名空间的名字,然后是一对大括号 {},括号的末尾不用加分号,其中包含命名空间的成员。命名空间可以定义变量、函数、子命名空间、类型等

例如小编定义了一个tmp变量:

cpp 复制代码
namespace MyNamespace
{
	int tmp = 0;
}

例如定义函数、变量、结构体:

cpp 复制代码
namespace MyNamespace
{
	//定义变量
	int tmp = 0;

	//定义函数
	int Add(int a, int b)
	{
		return a + b;
	}

	//定义结构体
	struct List
	{
		struct List* next;
		int data;
	};
}
嵌套命名空间

顾名思义,嵌套命名空间就是在基础命名空间里面在定义命名空间,例如:

cpp 复制代码
namespace MyNamespace
{
	//定义变量
	int tmp = 0;

	//定义函数
	int Add(int a, int b)
	{
		return a + b;
	}

	//定义结构体
	struct List
	{
		struct List* next;
		int data;
	};

	//嵌套命名空间
	namespace YourNamespace
	{
		int a = 10;
	}
}
匿名命名空间

顾名思义,匿名就是不去给这个命名空间设置名字,它的作用域仅在当前的编译单元(如:.cpp文件)内可见,例如:

cpp 复制代码
//匿名命名空间
namespace
{
	//定义数组
	int arr[10] = { 0 };
}

如何使用命名空间

完全限定访问

这种是访问类型是限定区域的,现用现拿,方式:空间名+双冒号+空间里面的成员对象

例如:

cpp 复制代码
//完全限定访问
int cur = MyNamespace::Add(5, 5);

嵌套空间的使用也一样:空间名+双冒号 + 使用对象(只不过这里的对象是另一个命名空间)

cpp 复制代码
//完全限定访问
int cur = MyNamespace::YourNamespace::a;
using 声明(局部引入)

相当于在局部告诉编译器,你要在这个局部使用这个空间里的某个对象,它相较于完全限定访问,范围稍微放大了一点,例如:

cpp 复制代码
//using 声明
using MyNamespace::tmp;

//可以直接使用tmp
int cur = tmp;
using namespace指令(全局引入)

这个很危险!属于 全局性的!导入定义的空间,就可以全局直接使用,例如:

cpp 复制代码
//全局导入使用
using namespace MyNamespace;

同样跨文件也是可以的,例如:

回顾整理

首先我们定义了某个命名空间,它的使用是很自由的

你可以选择限定访问,即仅仅对某个对象使用

还可以在某个函数内展开这个空间,那么这个空间仅仅在这个函数内生效

最后是最危险的行为!直接全局展开使用,包括跨文件。这样就无限制了

标准库的命名空间

我们既然可以自己命名空间,C++也有它自己的命名空间,我们称为C++标准库

C -> C++头文件的变化:

早期标准库将所有功能在全局域中实现,声明在 .h 后缀的头文件中,使用时只需包含对应头文即可

后来将其实现在 std 命名空间下,为了和 C 头文件区分,也为了正确使用命名空间, 规定C++头文件不带 .h

cpp 复制代码
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;

使用C++标准库进行输入输出:

  1. 使用 cout 标准输出对象(控制台)和 cin 标准输入对象(键盘)时,必须包含< iostream >头文件 以 及按命名空间使用方法使用std

  2. cout 和 cin 是全局的流对象,endl 是特殊的C++符号,表示换行输出,他们都包含在包含

< iostream >头文件中

  1. << 是流插入运算符, >> 是流提取插入符

  2. 使用C++输入输出更方便,不需要像 printf/scanf 输入输出时那样,需要手动控制格式。 C++的 输入输出可以自动识别变量类型,这时候就可以用流提取运算符

  3. 实际上 cout 和 cin 分别是 ostream 和 istream 类型的对象,>>和<<也涉及运算符重载等知识, 这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用

头文件与 std 的关系

C++原生头文件<iostream>,所有内容均在 std 内,使用时需要按命名空间使用方法使用std

比如我们使用<iostream>就可以代替原来的C中的各种头文件,例如:

cout 、cin、 endl 的深度解析

**注意:**使用 cout 标准输出对象(控制台)和 cin 标准输入对象(键盘)时,必须包含< iostream >头文件 以及按命名空间使用方法使用std

(1)std :: cout 表示标准输出流

输出通常缓存在内存中,直到遇到换行符**\n** 或者 std::flush 显示刷新

一般搭配 << (流插入运算符)使用,支持链式调用,例如:

cpp 复制代码
//链式输入
std::cout << "tmp:" << 42 << std::endl;
//非链式输入
std::cout << "tmp" << std::endl;

下面两种情况是区别不大的,加了 endl 只是可以换行,刷新c++的缓冲区的内容到文件

(2)std :: endl 流操纵符

它有两个作用:1、插入换行符"\n" 2、强制刷新输出缓冲区,即调用 std :: flush

频繁使用可能导致 I/O 性能下降,建议使用 \n 代替,例如:

(3)std :: cin 标准输入流

功能:从控制台读取用户输入

**>>**是流提取运算符,自动跳过空白字符

C++的输入输出可以自动识别变量类型,这时候就可以用流提取运算符

例如:

当流输入时不要加 std::endl ,可以这么理解:既然需要用户输入,加了endl 结束了还怎么输入?

常见错误

(1)没有用 std ::前缀

(2)随便使用 using namespace std

如果程序员定义了变量 rand ,但是C++标准库中也有对于 rand 的定义,这就导致了冲突报错

(3)输入与输出类型不匹配

总结

(1)std 是标准库的命名空间,任何标准功能都需要通过 std:: 访问

(2)需要清楚 cout、cin、endl、std 命名空间的对象

(3)尽量少用全局的 using namespace std ,使用优先顺序:全限定 -> 局部 -> 全局

【雾非雾】期待与你的下次相遇!

相关推荐
GISer_Jing10 分钟前
Three.js中AR实现详解并详细介绍基于图像标记模式AR生成的详细步骤
开发语言·javascript·ar
委婉待续13 分钟前
Qt的学习(一)
开发语言·qt·学习
笨笨马甲13 分钟前
Qt Quick Layout功能及架构
开发语言·qt
Dovis(誓平步青云)23 分钟前
探索C++标准模板库(STL):String接口的底层实现(下篇)
开发语言·c++·stl·string
海棠一号27 分钟前
JAVA理论第五章-JVM
java·开发语言·jvm
笑鸿的学习笔记1 小时前
虚幻引擎5-Unreal Engine笔记之SET节点的输出引脚获取设置后的最新变量值
笔记·ue5·虚幻
草莓熊Lotso1 小时前
【数据结构初阶】--算法复杂度的深度解析
c语言·开发语言·数据结构·经验分享·笔记·其他·算法
KyollBM1 小时前
【CF】Day75——CF (Div. 2) B (数学 + 贪心) + CF 882 (Div. 2) C (01Trie | 区间最大异或和)
c语言·c++·算法
海的诗篇_1 小时前
前端开发面试题总结-JavaScript篇(二)
开发语言·前端·javascript·typescript
feiyangqingyun1 小时前
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
c++·qt·udp·gb28181