🏠前言:
1. C++的诞生:
- 1979年,贝尔实验室的本贾尼等人试图分析unix内核的时候,试图将内核模块化,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称之为C with classes。
- 在我们之前的学习中,我们学习的C语言是面向过程的语言,在实现大型项目的时候往往要从底层原理编写,这样就不是很方便,而C++语言是面向对象的语言,它自己带有的一个STL库等一系列C++特有的东西让实现项目的时候会方便很多。
2. C++的应用领域:
- 操作系统以及大型系统软件开发
- 服务器端开发
- 人工智能
- 网络工具
- 游戏开发
- 嵌入式领域
- 数字图像处理
- 分布式应用
- 移动设备
3. 如何学习C++:
- 建议不要把 精通C++作为一个一年目标,应该要把学习语言作为一个持续的过程,同时要把语言运用在具体的应用场合中。
- 在学习的过程中要多实践,多去阅读相关书籍。
- C++的学习更像是一场漫长的修行,它更多需要的是时间和经验上的积累,要在磨练中成长,所以 路漫漫其修远兮,吾将上下而求索~~
4. 学习资源推荐:
适合学习C++查看相关库的网站: 👉 学习传送门1 👉学习传送门2
5. 在开启C++的学习之前我们先深深的膜拜一下: 🙏🙏🙏🙏
C++之父 —— 本贾尼·斯特劳斯特卢普(Bjarne Stroustrup) 感谢祖师爷能赏口饭吃!!
🚄1. 命名空间:
刚开始学习C++的时候,我们要知道的是C++是兼容C语言的,包的头文件是 #include < iostream >
解释:
- i 是 输入 input 的首字母,o 是输出 output 的首字母
- stream 是 流 的意思
- iostream 是输入输出流,也就是 C++中的标准输入输出流
1.1 C语言的命名冲突
在开始学C++的时候,开头往往会写 using namespace std,很多小伙伴知道要这么写,却不知道到这样写的原因是什么,下面我们就来好好絮叨絮叨……
1.在C语言有一个规定:
- 在同一个源文件中,发生在同一个作用域中的
- 函数名和函数名,变量名和变量名,函数名和变量名 都不能相同
- 例如定义一个 int ret = ret(),这种就形式在C语言中是不允许的
- 容易引起名称混淆,导致不容易维护,这也是C语言的一个缺陷
2. 日常问题:
#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
printf("%d\n", rand);
return 0;
}
假如我们不知道rand是一个函数,当定义一个rand的全局变量时,编译器处理的时候就会报错:
(1) 因为头文件stdlib.h中有rand函数,全局变量rand和库函数中的rand函数发生了命名冲突。 这就意味着我们在命名全局变量的时候,要还要顾及到库函数中的函数名,这对于使用者来说无疑是一种麻烦。
(2) 同时在我们日常分工写大型项目,特别是分组实现的时候,难免不同组会出现函数命名冲突的现象,一旦发生冲突,若是用C语言实现的话,重名的就一定要有一方作出让步,对重名函数作出修改,这也在无形之中,大大增加了工作量。
1.2 C++引入命名空间域
1.作用域的区别:
(1) 下面程序中a的值是多少:
#include<stdio.h>
int a = 10;
int main()
{
int a = 0;
printf("%d\n", a);
return 0;
}
- 我们在C语言中学过 (int a = 10) 中a是全局变量,(int a = 0) 中a是局部变量
- 当全局变量和局部变量重名的时候
- 主函数中访问的这个重名变量是以局部变量优先的
- 所以这个程序打印出的结果为 0
(2) 那如果我们想访问到全局变量中的a,将它打印在出来该怎么办呢:
- 这里介绍一个操作符:( ::),: : 域作用限定符 - 指定从左边的域找,左边是空白默认访问的是全局域的a
- 这样就 printf函数 访问到了全局域中的a
- 所以加了域作用限定符之后,这个程序打印出的结果为 10
2.C++为了填C语言这个坑,就引入了命名空间域 (namespace) :
将变量放在命名空间域里面和其他变量形成隔离
#include<stdio.h>
#include<stdlib.h>
namespace yy
{
int rand = 0;
}
int main()
{
printf("%d\n", yy::rand);
return 0;
}
- 这时程序打印出的结果为 0 ,就不会出现命名冲突的问题了
- 命名空间域的名字自己定,当要用到这个域中的变量时,运用域作用限定符来指定域访问,像结构体,但又不是结构体
- 命名空间中不仅仅可以定义变量,还可以定义函数,不仅仅可以定义函数还可以定义类型
- 命名空间不能放在main函数里面,只能放在全局中,也就是说不能在函数中定义,不能在局部定义
1.3 命名空间的合并与嵌套
多个同名的命名空间会被合并,见如下代码:
#include<iostream>
namespace yy
{
int num1 = 1;
}
namespace yy
{
int num2 = 2;
}
int main()
{
printf("%d\n", yy::num1);
printf("%d\n", yy::num2);
return 0;
}
- 同名的命名空间是可以同时存在的,编译器编译时会合并
- 这时程序打印出的结果为 1 和 2
命名空间可以嵌套使用,见如下代码:
#include<iostream>
namespace yy
{
int num1 = 1;
namespace zz
{
int num2 = 2;
}
}
int main()
{
printf("%d\n", yy::num1);
printf("%d\n", yy::zz::num2);
return 0;
}
- yy::zz::num2 的意思是找yy域中的zz域,再去找zz域中的num2
注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中,命名空间域不影响变量的生命周期
1.4 命名空间的使用
上文中其实已经介绍了命名空间的一种使用的方法,那就是用域作用限定符,还有两种使用方法:
1.使用 using namespace 命名空间名称引入:
- 这个可以理解成将命名空间中的成员全部释放出来
- 也就相当于让这个命名空间的隔离效果失效
- 展开命名空间,相当于没有命名空间了
#include<iostream>
namespace yy
{
int num1 = 1;
}
using namespace yy;
int main()
{
printf("%d\n", num1);
return 0;
}
- using namespace yy 这里的意思是,把yy这个命名空间的东西放出来
- 这时程序打印出的结果为 1
2.使用 using 将命名空间中成员引入:
- 这个可以理解成将命名空间中的成员单独释放出来
- 只有释放出来的成员不用域作用限定符访问
- 其余成员依旧需要用域作用限定符来访问
- 当然被单独释放的成员也可以用域作用限定符访问
#include<iostream>
namespace yy
{
int num1 = 1;
int num2 = 2;
}
using yy::num2;
int main()
{
printf("%d\n", yy::num1);
printf("%d\n", yy::num2);
printf("%d\n", num2);
return 0;
}
总结:
- 命名空间平时写练习就全部展开,但是全展开是不好的,存在冲突的风险
- 建议在项目里面去指定,或者是展开常用的,但是平时练习的时候没有那么讲究
- 指定展开或者是指定访问不方便,常见的就是全部展开
讲到这里我们应该能理解开头要写 using namespace std 的原因了:
- 因为 std 是C++标准库的命名空间 —— std 封C++库的命名空间
- 命名冲突 – C语言没有很好的解决这个问题,C++ 引入namespace 解决了这个问题
C++包头文件的几种方式(补充):
(1) #include< iostream >
- input output stream 输入输出流
(2) #include< iostream.h >
- 早期头文件特别早的编译器用这个头文件,如:VC6.0
- 当时没有命名空间,直接可以使用 cout
(3) #include<cstdio.h> 与 #include<cstdlib.h>
(4) #inlude<stdio.h> 与 #include<stdlib.h>
🚓2. C++的输入 & 输出:
1.标准输入输出:
- C++的输入是cin,输出是cout,包含< iostream >头文件,以及std标准命名空
间中 - cout 中的 c 是 Character OUTput stream 的首字母
- cin 中的 c 是 console —— 控制台,的首字母
2.操作符介绍:
- " >>" 流提取运算符,流提取 - 也可以叫输入
- cin >> a; 从输入流中提取出来流到 a
- "<<"流插入运算符, 流插入 - 也可以叫输出
- cout << a; 将a中的东西插入到cout(控制台)中去
- 这样更方便记忆~
#include<iostream>
using namespace std;
int main()
{
int a = 0;
cin >> a;
cout << a << endl;
return 0;
}
- cuot 和 cin 都是C++标准库中的,是被封在std命名空间中的
- 所以在使用之前要using namespace才能直接用
- 或者用域作用限定符指定使用,如:std::cout, std::cin
- 或者将cout和cin单独放出来使用
- endl是C++中的换行
2.特点:
(1) C语言的特点是 " 指定输入输出的类型 "
- printf是print format 格式打印
- scanf是scan format 格式输入
(2) C++的特点是 " 自动识别类型 " 和 " 一行输入输出多个 "
int main()
{
int a = 0;
double d = 0.0;
cin >> a >> d;
cout << a << ' ' << d << endl;
printf("%d %.2f", a, d);
return 0;
}
- printf 可以格式输出,对小数点后几位的控制输出很方便
- cout 要想控制位数输出的话不是不可以,是很麻烦
- 因为C++是兼容C语言的,所以遇到控制小数位数的输出最好用 printf
- 同时因为 scanf 是格式输入,而 cin 是要识别的
- scanf 相对于 cin 而言读取的速度更快,当然我们很难察觉
🚕3. C++的缺省参数:
3.1 缺省参数的概念
(1) 概念: 缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
- 在C语言中自定义的函数中,函数的形参是不可以赋值的
- 函数的形参是什么类型的值,实参就要传相应类型的值
- 而 C++ 它引入了缺省参数的概念,填补了C语言的不足
#include<iostream>
using namespace std;
void Print(int a = 10)
{
cout << a;
}
int main()
{
Print();
rturn 0;
}
- 当函数不传实参的时候,形参默认值是10
- 当函数传实参的时候,形参就是实参实际传的参数5
3.2 缺省参数的分类
1.全却省参数:
void Func(int a = 100, int b = 200, int c = 300)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
程序的结果是:100 200 300
2.半却省参数:
void TestFunc(int a, int b = 10, int c = 20)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
同时C++还支持半缺省参数,但是半缺省参数要注意几点:
(1) 半缺省参数必须从右往左依次来给出,不能间隔着给
- 因为传参的时候是从左往右传的
- 当缺省参数时不是从右往左依次来的话,就会产生歧义
(2) 缺省参数不能在函数声明和定义中同时出现
- 注意:如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。
(3) 缺省值必须是常量或者全局变量
(4) C语言不支持(编译器不支持)
|