TIPS
- C++是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式等
- C++总计63个关键字,C语言32个关键字,具体没有必要先不去管它
域,命名空间域与namespace关键字
- cpp需要解决的第一个问题就是命名空间的问题。
- 在之前讲的是在c语言的基础之上。假设现在先去定义一个全局变量rand,然后再main函数里面去编译打印变量一下,发现就是可以通过的。但是你只需要再加一个头文件stdlib.h,它就通不过了。为什么呢?
- 这时候你会发现他报错:重定义了。这边就是发生冲突了,变量命名的规则就是:比如说不能与关键字发生冲突,首字母必须是什么啊等等。但是他没有规定说变量名不能定义成rand,那这边发生冲突的一个原因就在于与库发生冲突了,因为stdlib.h里面有一个函数就叫做rand就是产生随机数的那个函数,因此名字就发生冲突了。
如上,这是C的一个缺陷之一。 - 因此c语言有命名冲突的问题,命名冲突主要有两方面:第一方面就是我们跟标准库冲突了,有些东西在库里中已经定义过了。最难受的是比如说你定义了一个变量,那我也不知道头文件里面的那些具体的细节是什么啊,诶突然有一天包了一个头文件上去发现就报错了,然后不包头文件就又不报错…所以说在c语言的大型项目有个很恶心的问题:有一天你把c语言的某个库给他引进来的话,第一步要解决的就是好多命名冲突问题,因为你这边定义的某个变量那个库里面也定义了相同名字的东西。
- 第二方面就在于:在公司里面是一个项目组,然后项目的话不是一个人独立完成写的。而是有很多小伙伴写的,那就有一种可能你写的与我写的发生冲突。这个完全避免不了。
域与命名空间域
- 其实之前在c语言的时候也有域这个概念提及(作用域就是域的一种,作用域分为全局域与局部域)
- 域有作用域(全局域,局部域),类域,命名空间域…
- 在同一个域里面,不可以定义同名的变量。但是在不同的域里面,就可以定义同名的变量。比如说同样是变量a可以放在局部域里面,也可以放在全局域里面。但会影响访问,也会影响生命周期。
namespace与命名空间域的定义
- 在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。
- 使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的
- namespace叫做命名空间,其实就是用来解决命名冲突的问题。这个关键字就可以定义一个域出来。如果想要不冲突,就可以用域去隔离。用命名空间就可以去定义一个命名空间域,就可以起到隔离效果。
- 然后这个namespace可以自己去创建一个命名空间域。当命名空间域,局部域,全局域这几个域全都同时存在的时候,然后比如说要去访问变量搜索的顺序优先是局部域,其次是全局域。如果说全局域也没有这个变量的话,如果你没有特别指定或者打开命名空间域,不会自动主动去命名空间域当中搜索。因此默认情况下是不会的。只有有两种可能性,他才会到命名空间域当中去搜索,1. 打开了命名空间域,2. 指定命名空间域搜索顺序(后面会讲)。
- 定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
- 在命名空间域当中,除了可以定义变量之外,还可以定义函数与类型等等,是个大杂烩
namespace sjy
{
int rand = 666;
int add(int a, int b)
{
return a + b;
}
typedef struct Stu
{
char name[10];
int age;
float score;
}Stu;
//.............
}
- 在c语言当中没有办法用命令名空间(压根没这玩意儿)去解决这个命名冲突的问题,而cpp有,C++的话本身有内置命名空间域std,比如说stl与cpp库都是定义在一个大的命名空间std当中。
- 一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
打开命名空间域 using namespace …(打开命名空间域本质就是融入到全局域当中)
- 展开命名空间域就是using namespace 命名空间域的名字,注意:std是标准库的命名空间域(内置).
#include <iostream>
namespace sjy
{
int rand = 666;
int add(int a, int b)
{
return a + b;
}
typedef struct Stu
{
char name[10];
int age;
float score;
}Stu;
//.............
}
using namespace std;
using namespace sjy;
- 易错点:在全局变量已经有a的情况之下,假设此时命名空间域当中也有一个a,然后我把命名空间域给他展开using namespace…
打开命名空间域本质就是融入到全局域当中,这时候这两个就不能够同时存在。
指定命名空间搜索顺序(域作用限定符)
- 访问的时候我们都知道遵循局部优先原则。那然后假设我在局部范围内已有该命名的情况下就想访问那个名字一模一样的全局变量嘞?
- 在cpp当中就有方法:用“: :”域作用限定符。在访问的时候默认显示在局部域搜索,局部有的话优先局部,如果在局部域中搜不到的话,就去全局域当中去搜索。这个域作用限定符表示去这个限定符左边这个域去搜索(有多个的话就从左到右这个命名空间搜索顺序),空白就代表直接全局域(也不需要去加空格)
- 在那些顺序当中,如果不加以人为干扰的话,局部域有了,全局域就不会继续在那里找下去。那我如果假设就想访问全局域的,就用 : : x就可以了。那我如果假设就想访问命名空间域的,就用 命名空间域名字 : : x
- 不同的域当中完全可以存在名字相同的变量,默认访问的是局部域,然后全局域,然后命名空间域的话就看他打不打开,或者我直接指定顺序访问
针对头文件的一些说明
- 头文件实际上就代表着他所分装的一个代码块而已。当在开头把头文件怎么写好之后,等会儿在预处理编译阶段就会把这个头文件所对应封装的一个代码块直接拷贝到那个开头。
- 但该打开命名空间的还是得打开,不然的话,编译其实不认得那些代码里面的命名符号
- 在C++里面的头文件是没有.h了的
- C++的stl与标准库有着各种各样,形形色色的头文件,但由于stl与标准库都是在内置的命名空间域std当中,所以说要真正使用的话,要么就是去打开std(或者部分打开),要么就是用域作用限定符去指定命名搜索顺序
- 比如说在头文件stdlib.h当中有一个rand,然后把这个头文件给他include一下,那么相当于就把这个头文件当中的所有内容拷贝到那个地方去,所以说相当于就是在全局范围当中已经有一个rand,如果说此时想要再去定义一个rand的变量就要给他放到一个域当中,但对于这个命名空间域的话,不能够随意展开。不然又裂开了,当命名空间域打开之后,相当于已经融入到了全局域当中,此时此刻命名空间域当中有一个名称rand,stdlib.h当中也有rand,不就又冲突了嘛
- 头文件的内容展开Include一下,相当于就是说把头文件当中的内容给它包含在这上面,拷贝到那个地方去;命名空间域的展开using namespace就是决定编译时是不是到这个空间域当中去搜索一下
命名空间域的嵌套与合并
- 命名空间与相互之间可以互相嵌套,namespace嵌套namespace在嵌套namespace,在不同命名空间当中,当然是可以去创建相同名字的变量。因为这些相同名字的变量之间互不干涉与影响。
- 在同一个命名空间域当中,如果又会存在命名冲突的话,就在命名空间里面再去嵌套命名空间。
- 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中
- 这个的话举个很明显的例子就是说:比如说C++里面的stl与标准库的话,有各种各样很多的头文件,然后再分别写里面,在实现这些头文件的时候,由于我们知道必须是在一个规划好的命名空间域当中,比如说有50个头文件,然后每个头文件里面在代码实现的时候都namespace std1…最后总的合起来会把这些命名空间域std1全部合成起来归为一个
实际对命名空间域std展开的提醒(部分打开命名空间域)
- 日常练习可以using namespace std全部展开
- 但是在实际写项目的过程当中,并不建议直接把命名空间域std直接全部展开,因为一旦把命名空间域std全部展开的话,相当于与全局域已经融为一体。这时候已经写好的在全局域当中的代码可能会与标准库,stl当中的代码发生命名冲突,改起来会非常麻烦
- 项目只建议指定访问,不要轻易展开命名空间
- 在实际应用当中就是经常是把那些常用的函数,变量等等给它展开,不是直接using namespace std 全部一把展开,采用的是部分展开的方式,把那些常用的给他都展展开,然后其他不常用的用一个域作用限定符去指定一下命名搜索顺序,临时访问一下就可以
C++的输入与输出 cin && cout && endl 简单介绍
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
- cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,相当于换行符\n,他们都包含在包含< iostream >头文件中。
- <<是流插入运算符,>>是流提取运算符。
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
- 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有有一个章节更深入的学习IO流用法及原理。
- cin连续输入的时候,就用多个流提取运算符给他串起来就可以,非常快捷
- cout连续输出的时候,也是用多个流插入运算符串起来,如果说没有在中间加入空的话,那么这些东西都是紧挨着连成一串的
- 注意:他们自动识别类型的,不需要你去多考虑