C++入门基础:引用,auto自动关键字,内联函数,范围for循环
引用:
在C++中引入了一个新的很重要的概念:引用,引用不是定义了一个新变量,而是给已存在的变量取一个别名,和已存在的变量共用一块内存空间。
#include<iostream>
using namespace std;int main()
{int i = 10;int& num = i;//定义引用类型cout << &i << endl;cout << &num << endl;
}
可以看到 num和 i 的地址是相同的,所以引用是和变量共用一个内存空间,相当于给他取一个别名。
引用的特性:1.引用在定义时必须初始化。2. 一个变量可以有多个引用,多个别名。3.引用一旦引用一个实体,再也不能引用其他实体。
引用的使用:
做参数:
void swap(int& left, int& right)
{int tem = left;left = right;right = tem;
}int main()
{int i = 10;int j = 20;cout <<"i :" << i <<"j :" << j << endl;swap(i, j);cout << "i :" << i << "j :" << j << endl;
}
在C语言时,我们在函数内部交换值的话,得解引用指针才行,引用不需要。
引用当作参数有什么优点吗,当然,以前如果传值的话,函数内部还是会开内存拷贝对应的值,如果对象较大,可能会影响效率,引用就直接引用对象的空间,减少拷贝,提高效率。对比指针来说,引用相对更加安全,不能修改指向,也不容易有野引用。
做返回值:
int& count()
{++a;return a;
}int main()
{int& i = count();cout << i << endl;cout << a << endl;++i;cout << i << endl;cout << a << endl;
}
当返回值时,引用就可以修改返回对象,并且可以减少拷贝提高效率。这是为什么呢?
如图所述,返回值就会有拷贝。但是一般我们不用引用当返回值,因为我们函数返回时,出了函数作用域,返回对象一般会销毁,销毁之后则不能用引用返回,虽然内存还在(而且引用还在引用这个内存,下次系统给这个内存存数据,引用也会跟着变),但是空间使用权已经还给系统了。所以返回对象不在了就必须用传值返回。
常引用:
引用可以给常量用吗?或者说具有常量属性的。答案是不可以,普通的引用不可以:
因为常量是不可以被修改的,但是引用之后权限被放大了,因为引用是可以被修改的,系统只允许权限平移和缩小,不能放大。
加上const之后就可以了,之后引用也不能被修改了。
还有一种情况,就是具有常量属性的值:临时对象,表达式。隐式类型转换中间就会生成临时对象:
从double到int会隐式类型转换,所以 int& 无法接收,加个const就行了。
引用和指针的不同:
引用和指针得从两个方面来看:
1.语法:从语法上引用就是一个别名,没有独立空间,和被引用的实体共用一个空间,而指针就是空间的地址,有自己的大小:4/8个字节。
2.底层:其实引用在底层实现上是有空间的,因为引用是按照指针方式来实现的。
总结不同点:1.引用必须初始化,指针没规定。
2.引用在初始化引用一个实体后,就不能再引用其他实体,而指针可以在任何时候改变指向。
3.没有NULL引用,但是有NULL指针
4.在sizeof中含义不同:引用的结果为引用类型的大小,而指针就是地址空间的大小(4/8个字节)
5.有多级指针,但是没有多级引用
6.指针需要*解引用访问实体,引用不需要。
7.引用比指针使用安全,因为不容易有野引用。
8.引用加是引用的实体加,指针是偏移一个类型的大小。
auto自动关键字:
auto关键字在C++98 和 C++11是两种含义,现在的主流含义都是用C++11里的,也就是自动识别变量类型的指示符,编译器会在编译阶段自动推导变量类型。
因为有时候我们的类型会变得难于拼写,含义不明确,所以使用auto方便。
注意 :使用auto必须初始化,因为编译器要通过初始化表达式来推导类型。
auto也可以和指针引用一起使用,但是用auto定义指针变量时,加不加*都可以,但是声明引用时必须加&符号。
在同一行声明多个变量时,这些变量必须是相同的类型,因为编译器只会通过第一个类型推导,然后再用推导出来的定义剩下的。
auto不能用的场景:
1.不能作为函数的参数
2。不能声明数组。
范围for循环:
在C语言中我们的for循环是知道的,在C++中引入了一个更方便的基于范围的for循环:
这就是基本使用方法,自动迭代,自动判断结束(可以用continue结束本次循环,和break结束整个循环),依次取arr数组的值赋值给i。
因为是赋值给 i 的,所以想改变数组里的值可以用引用接受:
使用范围for要注意:迭代的范围必须是确定的。(ps:在一个类里要使用范围for要实现了迭代器)
内联函数:
内联函数概念:inline修饰的函数就是内联函数,编译时编译器会在调用内联函数的地方直接展开函数内容。减少了调用开销,提高效率。
这一点很像宏,但是宏缺点很多:1.语法复杂。2.不能调试。3.没有类型安全的检查。
特性:
1.内联函数是一种空间换时间的做法,但是可能会使目标文件变大,所以建议调用多且不是递归的小函数使用内联。递归编译器会忽略inline特性。
2.inlin对于编译器只是一个请求,编译器也许会忽略,要看编译器的内部实现。
3.内联函数不建议声明和定义分离,会导致链接错误。内联函数是不进符号表的。