👦个人主页:@Weraphael
✍🏻作者简介:目前学习C++和算法
✈️专栏:C++航路
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨
前言
本章是补充
C
语言语法的不足,以及C++
是如何对C
语言设计不合理的地方进行优化的。
目录
一、C++输入和输出
既然学习一门新的语言,那就少不了输出hello world
#include<iostream>
using namespace std;
int main()
{
cout<<"Hello world"<<endl;
return 0;
}
- 使用
cout
标准输出对象和cin
标准输入对象时,必须包含<iostream>
头文件以及按命名空间std
。endl
是特殊的C++
符号,表示换行输出,他们都包含在包含<iostream>
头文件中。<<
是流插入运算符,>>
是流提取运算符- 使用
C++
输入输出更方便,不需要像printf/scanf
那样,需要手动控制格式。C++的输入输出可以自动识别变量类型!但C++
也可以格式化输入输出,但比较复杂,如果题目要求格式化输入输出,可以使用printf
和scanf
,因为C++
兼容C
语言。
格式化输出模板
#include <iostream>
#include<iomanip>
using namespace std;
int main()
{
double pai = 3.1415926;
// 保留3位小数
cout << fixed << setprecision(3) << pai << endl;
return 0;
}
二、问题引入
来看看以下简单的C
语言程序:
首先它是能在VS
上编译通过,并且在屏幕上打印了rand:666
。但接下来加上头文件#include <stdlib.h>
,代码是否还能正常输出呢?
rand
重定义,这是为什么?
原因是:rand
是stdlib
库中的一个函数(如下图所示),在预处理阶段,#include <stdlib.h>
就会被展开(相当于全局有一个rand
函数),因此导致变量名和库函数相同,引发了 命名冲突问题。
【总结】
C语言存在命名冲突问题:
- 可能与函数库中冲突。
- 可能与同组开发冲突。
因此,为了解决C语言命名冲突问题,C++引入了namespace
这个关键字,用来定义一个命名空间域,其作用可以防止命名冲突问题。格式如下:
//name -- 名字随便取
namespace name
{
int rand = 666;
}
三、什么是域
域分为全局域、局部域、命名空间域,当然还有类域(后面博客会详细讲解)
3.1 全局域和局部域
main
函数外的变量称为全局域,main
函数内部的变量则称为局部域。而且,以上的代码是可以编译成功,因为 不同的域可以定义同名变量,但相同的域不能定义同名变量;并且 当全局域和局部域命名冲突时,优先访问局部域(局部域优先)
3.2 命名空间域
3.3 如何同时访问三个域的变量
如果当全局域、局部域和命名空间域发生命名冲突,正常来说局部域是直接访问,并且如果全局域出现同名遍历,我还想访问全局域;以及如何访问命名空间域的变量?
- 局部域没什么好说的,直接访问
- 当局部域和全局域同名时,并且还想访问全局变量,那就使用
::
—> 域作用限定符。表示变量a
去域作用限定符左边空白搜索,而这个空白代表的是全局域。- . 同理地,若想访问命名空间域的变量,在域作用限定符前加上命名空间域的名字即可,表示的是变量
a
去wj
这个域搜索变量
3.4 三种域访问的优先问题
当全局域、命名空间域和局部域同时存在,根据变量搜索原则,优先访问的是局部域
如果没有同名的局部变量,那么毫无疑问优先访问全局域
但是,它不会直接去命名空间搜索。那么怎样才能访问命名空间域里的变量呢?请继续往下看
3.5 访问命名空间域的方法
- 指定访问(域作用限定符)
- 展开命名空间域
展开的本意就是暴露到全局
3.6 解答标题的问题
因此,using namespace std
的意思就是展开标准库std
的命名空间,而标准库std
提供了大量常用功能的库,包括输入输出 <iostream>
、字符串<string>
、容器<vector>
等等。
四、使用using namespace的危害
注意:如果使用using namespace
直接展开命名空间域,在编译阶段就会去命名空间域搜索,就相当于暴露在全局环境下了(相当于全局变量)。因此,如果全局域也有一个命名相同的变量,就会产生命名冲突,也就报错了。
【总结】
从此可以看出,其实使用using namespace
的效果也是不佳的,因为它把命名空间展开后,域中的变量就相当于全局变量,而命名空间域的意义就是为了防止命名冲突的。因此不能轻易展开命名空间。(注意:这里的展开是代码编译阶段是否去命名空间搜索,而#include
是在预处理阶段就会被替换。)
【建议】
- 建议在写项目不要使用
using namespace
,using namespace std
展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数
,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现错误。
所以建议在项目开发过程中使用指定访问
或者可以部分展开
- 在日常练习中,建议直接
using namespace std
即可,这样就很方便
五、命名空间的嵌套
命名空间是允许嵌套的。
【输出结果】
ps:嵌套可以存在有同名变量(因为是不同的作用域),例子如下:
【输出结果】
需要注意的是:同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。因此,名称相同的命名空间是不允许定义同名变量的