文章目录
- 1. 学习c++之前的开胃菜
- 2. c++的发展历程
- 3. c++参考文档
- 4. c++的第一个程序
- 5. 命名空间
- 5.1 关键字namespace
- 5.2 namespace的嵌套使用
- 5.3 命名空间的使用
- 6. c++输入和输出
- 7. 缺省参数
- 8. 函数重载
- 9. 引用
- 9.1 引用的使用
- 9.2 const引用
- 9.3 引用和指针的关系
- 10. nullptr
- 11. inline修饰内联函数
- 12. 补充知识点(编译和链接)
1. 学习c++之前的开胃菜
估计大家刚开始学习c++之前,都觉得这门语言忒难,可是为什么大家还是毅然决然的选择了他呢?反过来讲,既然选择了计算机这条路,那么有哪条路又是好走的,如果你感觉现在学的很吃力,那么恭喜你,说明你正在走上坡路,无数个日夜,你努力啃着晦涩难懂的代码,终究有一天,你会将他们全部弄懂,就像翁凯老师讲的“计算机里没有黑魔法,它也是人为创造出来的,只是以我们当前的学识还不能理解,但终有一天我们会全部搞懂那些曾经自以为晦涩难懂的代码”
觉得计算机难学的集合了
好了,接下来进入我们今天的主题,就由我来为大家打开c++的大门
2. c++的发展历程
c++最初是由Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)1983年在贝尔实验室设计出了它,在1997年11月14日,联合标准化委员会通过了它的最终草案,并在1998年c++投入使用
另外c语言也是从贝尔实验室出来的,下面的两张图片就是c++的创始人
|
|
3. c++参考文档
- c++非官网文档
- c++官网文档—中文
- c++官网文档—英文
4. c++的第一个程序
- c++中需要将文件后缀定义为.cpp
- 当然,c++也兼容了c的语法,c之前的输入输出也能在cpp文件中运行
- c++也有自己的一套输入输出语法
这里不懂也没关系,接下来我们一一讲解
5. 命名空间
5.1 关键字namespace
- 在c/c++中,变量、函数和c++中的类都是大量存在的,这些变量和函数、类的名字可能会出现重复的风险,最终会导致编译器报错。而c++就引入了命名空间,关键字是namespace
- 使用命名空间后,可以对标识符的名字进行封装,避免重名的冲突
- c++标准库都放在一个叫std(standard)的命名空间中,因此我们经常看见using namespace std;这里的using是展开c++标准库的意思,后面会讲到
- 从这里可以看出,namespace对变量、函数等进行封装后,就可以避免命名冲突的问题
- namespace后面+命名空间的名字,大括号里面的都是命名空间的成员
- namespace本质上是定义了一个域,之前我们学过全局域和函数局部域,而namespace定义的这个域跟全部域各自独立,全局域和局部域是有生命周期的
- c++中有函数局部域、全局域、命名空间域、类域,而类域和命名空间域是不影响变量的生命周期的
- 另外再补充一点,上述图片中c++的namespace定义的命名空间成员rand其实就是一个全局变量,只不过namespace给它封装起来而已
5.2 namespace的嵌套使用
- namespace只能定义在全局,当然它也可以嵌套使用
::
是namespae的访问操作符号
- namespace定义结构体成员
- 项目工程中多个文件定义的namespace重名时,编译器会认为那是同一个namespace,不会冲突
5.3 命名空间的使用
- 编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找
- 因此访问命名空间内的成员时,一般采用指定的访问操作符
::
- using可以将命名空间内的某个成员展开,在项目中经常访问的不存在冲突的成员推荐这种⽅式
- 展开命名空间中全部成员,项目不推荐,冲突风险很大,日常练习程序为了方便推荐使用
- using展开命名空间成员后,则不用每次都输入访问符
::
来访问其内的成员了,但一般只在练习中使用
6. c++输入和输出
- <iostream> 是 Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象
- std::cin 是 istream 类的对象,它主要面向窄字符(narrow characters (of type char))的标准输入流
- std::cout 是 ostream 类的对象,它主要面向窄字符的标准输出流
- std::endl 是一个函数,流插入输出时,相当于插入一个换行字符加刷新缓冲区
- <<是流插入运算符,>>是流提取运算符。(C语言还用这两个运算符做位运算左移/右移)
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入、输出可以自动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是C++的流能更好的支持自定义类型对象的输入输出
- IO流涉及类和对象,运算符重载、继承等很多面向对象的知识,这个以后我们会讲到
- cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间去使用他们
- 一般日常练习中我们可以using namespace std,实际项目开发中不建议using namespace std
- vs编译器不包含<stdio.h>头文件也可以使用scanf/printf函数,这是因为<iostream.h>头文件间接包含了,但其他编译器可能未包含
- 还有一点需要注意的是,c++添加了命名空间后,对于头文件的包含,可以省去.h,也就是<iostream.h>可以写成<iostream>的形式
刚接触到这么多新的知识,看起来是不是有点懵,接下来我将通过图解示范帮助大家快速入门
- 从以上例子可以看出,c++在采用输入输出流后,再也不需要限定输入输出变量的格式,因为编译器会自动识别变量类型
7. 缺省参数
- 缺省参数就是在声明或者定义函数时为函数的参数指定一个缺省值,在调用该函数时,如果没有指定该参数的值,默认采用该缺省值,否则使用指定的实参,有时也将缺省参数叫做默认参数
- 函数定义和函数声明分离时,两者只需其一含缺省参数即可,不可两者都含缺省参数,因为这样编译器也不知道要采用谁的缺省值,会报错
- 缺省参数也分为全缺省参数和半缺省参数,其中全缺省参数就是函数的形参全部给定缺省值,而半缺省参数就是部分形参给定缺省值
- c++规定半缺省参数必须从右到左依次连续缺省,不能间隔跳跃给定缺省值
- c++规定带缺省参数的函数调用,必须从左到右依次给实参,不能跳跃给实参
8. 函数重载
- C++支持在同⼀作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调用就表现出了多态行为,使用更灵活。C语言是不支持同一作用域中出现同名函数的
- 构成函数重载:函数名相同,参数类型或参数个数不同
9. 引用
- 引用不是新定义了一个变量,而是给变量起了一个别名,编译器也不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
- 引用的格式:<code>类型& 引用别名 = 引用对象</code>
- 引用在使用之前必须初始化
- 引用只能引用一个实体,再不能引用其他实体
9.1 引用的使用
- 引用主要用于引用传参和引用做返回值,用于减少拷贝,来提高程序运行的效率,同时在改变引用对象的同时,还可以改变被引用对象
- 引用传参和指针传参类似,不过引用传参更为方便
- 引用返回值的场景较为复杂,这里只作为简单介绍,后续补充
- 引用和指针相辅相成,两者有许多重叠的地方,重叠的地方在c++里面一般都用引用,而像数据结构中的链表、二叉树等,还是用指针,因为引用不能改变指向,指针可以
9.2 const引用
- const引用对象时,权限不能放大,只能平移或者缩小权限
- 不需要注意的是类似
int& rb = a*3; double d = 12.34; int& rd = d;
这样⼀些场景下a*3
的和结果保存在⼀个临时对象中,int& rd = d
也是类似,在类型转换中会产生临时对象存储中间值,也就是时,rb和rd
引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以- 所谓的临时对象,就是编译器需要一个空间暂存表达式的求值结果时,临时创建的一个未命名的对象,c++把这个未命名对象称为临时对象
9.3 引用和指针的关系
- c++中指针和引用就像是亲兄弟,指针是哥哥,引用是弟弟,实践中它们相辅相成,功能有重叠性,互相不可替代
- 语法上引用只是一个变量的别名,不开辟内存空间,而指针要存储变量地址,需要开辟内存空间
- 引用在定义时必须初始化,而指针最好也初始化,不强制
- 引用在初始化引用一个对象后,不能再引用其他对象,而指针可以不断更改指向对象
- 引用可以直接访问引用对象,而指针需要解引用
- sizeof中含义不同,在指针中地址空间所占字节个数为4/8个字节,而引用中sizeof则表示引用对象类型的大小
- 指针容易出现空指针和野指针的问题,而引用很少出现,相对较安全
10. nullptr
- 在c语言中,经常用NULL为指针进行初始化,而在c++中NULL被定义字面常量0,在c中它被定义为(void*)的常量
- C++11中引用了nullptr,它是一个关键字,是一种特殊类型的字面量,它可以转换为任意其他类型的指针类型,使用nullptr定义空指针可以避免类型转换的问题,因此nullptr只能被隐式转换为指针类型,不能转换为整型
11. inline修饰内联函数
- 用inline修饰的函数就叫内联函数,编译器C++编译器会在调用内联函数时展开内联函数,这样就不用在调用函数时建立栈帧了,可以提高运行效率
- 内联函数对于编译器而言只是一个建议,通俗点讲,加inline修饰函数后,调用内联函数时编译器也可能不会展开,依旧会创建函数栈帧,所以函数不是+inline修饰后就必须展开
- 内联函数的使用场景一般是针对那些代码较短,频繁调用的函数,而像递归、代码较长(一般在10行及以上,并不准确,根据编译器而定)并不会展开内联函数,在VS2022编译器debug模式下也不会展开,因为内联函数不可以调试
- C语言中曾学过宏,宏就是用来替换宏体的,但是由于宏函数实现复杂且容易出错,C++提出的内联函数就是用来替换C语言中的宏函数
- inline不建议将内联函数的声明和定义分离放在两个文件,因为这样会导致链接失败,因为内联函数展开,就没有了函数地址,链接时就会报错
12. 补充知识点(编译和链接)
- 如何改变这种情况呢?