目录
[2.1 namespace的价值](#2.1 namespace的价值)
[2.2 namespace 的定义](#2.2 namespace 的定义)
[4.缺省参数 在形参的后面给一个赋值符号,再给一个值](#4.缺省参数 在形参的后面给一个赋值符号,再给一个值)
[6.5 指针和引用的关系](#6.5 指针和引用的关系)
1.C++的第一个程序
C++版本的hello world
2.命名空间
2.1 namespace的价值
使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的
包含了一个头文件,头文件在预处理阶段会展开,也有一个叫rand的函数
库里面用rand定义了一个函数,我们又用rand定义了一个变量
会出现命名冲突
2.2 namespace 的定义
1)定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员,命名空间中可以定义变量/函数/类型等
2)namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand不再冲突了
++不同的域可以定义同名,同一个域不能定义同名的东西++
C++规定用任何的变量或函数必须找到它的出处(定义),找不到就会报错
其实都是全局的变量,函数,类型,只是用域做了隔离
访问
3)C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域不影响变量生命周期
4)namespace只能定义在全局,不能在局部域里面嵌套定义(它的本质就是想和全局的进行隔离)
当然它还可以嵌套定义
是为了解决命名冲突的问题
访问
5)项目工程中多个文件中定义的同名namespace会认为是一个namespace,不会冲突
6)C++标准库都放在一个叫std(standard)的命名空间中
2.3命名空间的使用
编译查找一个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找,所以下面编译会报错
所以我们要使用命名空间中定义的变量/函数,有三种方式
1)指定命名空间访问(项目推荐这种方式)
2)using将命名空间中某个成员展开(项目中经常访问的不存在冲突的成员推荐这种方式)
3)展开命名空间中全部成员(项目不推荐,冲突风险很大,日常小练习程序为了方便推荐使用)
冲突风险
3.C++输入&输出
1)<iostream>是Input Output Stream的缩写,是标准的输入,输出流库,定义了标准的输入,输出对象
2)std::cin是istream类的对象,它主要面向窄字符的标准输入流
3)std::++c++out是ostream类的对象,它主要面向窄字符的标准输出流
字符
4)std::endl是一个函数,流插入输出时,相当于插入一个换行字符加刷新缓冲区
5)<<是插入运算符,>>是流提取运算符(C语言还用这两个运算符做运算左移/右移)
6)使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型(本质是通过函数重载实现的),其实最重要的是C++的流能更好地支持自定义类型对象的输入输出
7)IO流涉及类和对象,运算符重载,继承等很多面向对象的知识
8)cout/cin/endl 等都属于C++标准库,C++标准库都放在一个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去用他们
9)一般日常练习中我们可以使用using namespace std,实际项目开发中不建议using namespace std
10)这里我们没有包含<stdio.h>,也可以使用printf和scanf,在包含<iostream>间接包含了
4.缺省参数 在形参的后面给一个赋值符号,再给一个值
1)缺省参数是声明或定义时为函数的参数指定一个缺省值,在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省
2)全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值(默认值)
传参的时候只支持连续传,不支持跳越传
Func1(,2,); 错误的
C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值
3)带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参
4)函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值
5.函数重载
C++支持在同一作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同,这样C++函数调用就表现出了多态行为,使用更加灵活,C语言是不支持同一作用域中出现同名函数的
//参数不同构成函数重载
//返回值类型不同不构成重载
//
6.引用
6.1引用的概念和意义
引用不是定义一个变量,而是给已存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
类型& 引用别名=引用对象;
//改变别名也就会改变原来的
//
rx是a的别名,ry是e的别名
//
//图中是错误的,phead是plist的别名,改变phead也就改变了plist
6.2引用的特性
1)引用在定义时必须初始化
2)一个变量可以有多个引用,还可以重引用
3)引用一旦引用一个实体,再不能引用其他实体(只能作为一个变量的别名,不能再成为其他变量的别名)
6.3引用的使用
1)引用在实践中主要是于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象
2)引用传参跟指针传参功能是类似的,引用传参相对更方便一些
引用返回值的场景相对比较复杂
3)引用和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代
C++引用定义后不能改变指向,Java的引用可以改变指向
4)一些主要用C代码实现版本数据结构教材中,使用C++引用替代指针传参,目的是简化程序,避开复杂的指针
6.4const引用
1)可以引用一个const对象,但是必须用const引用,const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大
(可以引用:1.const对象 2.普通对象 3.临时对象)
//
2)需要注意的是类似int& rb=a*3;double d=12.34;int& rb=d;这样一些场景下a*3的和结果保存在一个临时对象中,int& rd=d也是类似,在类型转换中会产生临时对象存储中间值,也就是说rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以
3)所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名的对象叫做临时对象
6.5 指针和引用的关系
C++中指针和引用在实践中相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代
1)语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量的地址,要开空间
2)引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的
3)引用在初始化时引用一个对象后,就不能再引用其他对象,而指针可以再不断地改变指向对象
4)引用可以直接访问指向对象,指针需要解引用才是访问指向对象
5)sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数
(32位平台下占4个字节,64位下是8个字节)
6)指针很容易出现空指针和野指针问题,引用很少出现,引用使用起来相对更安全一些
7.inline
1)用inline修饰的函数叫做内联函数(是可以调试的),编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率
2)inline适用于频繁调用的短小函数,对于递归函数,代码相对多一些的函数,inline会被编译器忽略
3)C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错,且不方便调试,C++设计inline的目的就是替代C的宏函数
4)VS编译器debug版本下面默认是不展开inline的,这样方便调试,debug版本想展开需要设置
这样就展开了(反汇编)
Add相对较长就不展开了,inline对于编译器是一个建议,编译器才具有最终决策权
5)inline不建议声明和定义分离到两个文件,分离会导致连接错误,因为inline被展开,就没有函数地址,连接时会出现报错
8.nullptr
NULL实际上是一个宏,在传统的C头文件(stddef.h)中,可以看到
1)C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量,不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,本想通过 f(NULL)调用指针版本的 f(int*)函数,但是由于NULL被定义成0,调用了 f(int x),因此与程序的初衷相悖。f((void*)NULL); 调用会报错
2)C++中引入nullptr,nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型,使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型