菜鸟笔记
提升您的技术认知

C++入门(二)

C++入门(二)

  • 1.引用
    • 1.1引用概念
    • 1.2引用特性
    • 1.3常应用
    • 1.4使用场景
    • 1.5传值、传引用效率比较
    • 1.6引用和指针的区别
  • 2.内联函数
    • 2.1概念
    • 2.2内联函数的特性
  • 3.auto关键字(C++11)
    • 3.1auto使用细则
  • 4.基于范围的for循环(C++11)
  • 5.指针空值nullptr(C++11)

1.引用

1.1引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共同用一块内存空间。
格式:类型& 引用变量名(对象名)=引用实体

1.2引用特性

1.引用类型必须和引用实体是同种类型的

2.引用在定义时必须初始化

3.一个变量可以有多个引用

4.引用一旦引用一个实体,再不能引用其他实体

1.3常应用




指针和引用,在赋值和初始化时,权限可以缩小,但是不能放大

1.4使用场景

①做参数

上图是以前我们如何交换两个值的

我们不用再像以前一样用指针,过于麻烦,用引用更加好理解,就是给x和y取了个别名而已
这样形参改变,影响实参,我们称之为输出型参数
②做返回值

在函数返回的时候,分为这个变量是否在出了函数作用域就销毁的情况。如果是一般的返回,就是传值返回,无论是否出作用域销毁,他都会创建一个常属性的临时变量,然后回到主函数,赋值给相应的变量。如果是局部变量,也就是出了作用域就销毁的变量,在返回的时候,只能依照上面的办法,因为局部变量在函数栈帧销毁时,也可能一并销毁变成了随机值。但如果是一个全局变量,则可以使用传引用返回,因为全局变量出了作用域不会销毁。

注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给操作系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

1.5传值、传引用效率比较



从上图中可以看出传值和传引用的效率相差还是很大的。
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的临时拷贝,因为用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

1.6引用和指针的区别


在汇编代码上可以看见引用和指针的操作是一样的,是不是非常震惊。其实本质上在底层实现上实际是有空间消耗的,因为引用是按照指针来实现的,在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

引用和指针的不同点:
①引用概念上定义一个变量的别名,指针存储一个变量的地址
②引用在定义时必须初始化,指针没有要求
③引用初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
④没有NULL引用,但有NULL指针
⑤在sizeof中含义不同;引用结果为引用类型的大小,但指针始终是地址空间所占字节个数
⑥引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
⑦有多级指针,但没有多级引用
⑧访问实体方式不同,指针需要显式解引用,引用编译器自己处理
⑨引用比指针使用起来相对更安全

2.内联函数

2.1概念

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
查看方式:
1.在release模式下,查看编译器生成的汇编代码中是否存在call 函数名,但是由于系统会给大量优化,可能看不出,因此我们推荐下面一种方法
2.在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进行优化,方便调试)


按照上面的方法调整一下项目的属性就可以查看内联函数的展开了

通过右边的汇编,可以看出,Add函数直接在调用的地方展开了,并没有call Add来调用函数的指令

2.2内联函数的特性

①inline是一种以空间换时间的做法,这里的空间指的是最后生成的exe文件,因为如果你调用这个函数的次数多了,那么函数每次都展开,他的代码量就上去了。如果编译器将函数当成内联函数处理,那么在编译阶段,会用函数体替换函数调用
②inline对于编译器而言只是一个建议,不同的编译器关于inline实现的及机制可能不同,一般建议将函数规模小、不是递归、且频繁调用的函数采用inline修饰,否则编译器将会忽略illine的特性

当我把代码写的稍微复杂并多一点的时候,编译器直接忽略了inline,并调用了Add函数,从右侧的汇编中就能详细看出,编译器call Add
③inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到

3.auto关键字(C++11)

auto作为一个类型指示器来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

3.1auto使用细则

①使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一个类型的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量的实际类型
②auto与指针和引用相结合起来使用:用auto声明指针类型时,用auto*和auto没有任何区别,但用auto声明引用类型时必须加&

③在同一行定义多个变量:当在同一行声明多个变量时,必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量

④auto不能作为函数的参数

⑤auto不能直接用来声明数组

4.基于范围的for循环(C++11)


如果想要改变数组的元素,就可以用到前面学习的引用

for循环后的括号由冒号:分为两部分:第一个部分是范围内用于迭代的变量,第二部分则表示被迭代的范围
使用条件:
1.for循环迭代的范围必须是确定的,对于数组而言就是数组的第一个元素和最后一个元素的范围
2.迭代的对象必须要实现++和==的操作
现在只要掌握怎么用就好,现在毕竟是C++入门,后面会详细讲的

5.指针空值nullptr(C++11)


对于NULL的定义就是如果使用了C++,那么NULL就为0,因此下面的代码就会出现问题,只能把NULL强制转换为int才能得到想要的结果

因此C++11引入了nullptr
注意:
①在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
② 在C++11中,sizeof(nullptr) 与 sizeof((void
)0)所占的字节数相同。
③为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。