C++中引用知识点
Chaser Feng 人气:0引用的概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。那么这里的“铁牛”、“黑旋风”就称李逵的引用。
在程序中呢,引用的用法如下:
类型& 引用变量名(对象名) = 引用实体;
举个例子:
void TestRef() { int a = 10; int& ra = a;//<====定义引用类型 printf("%p\n", &a); //打印出a的地址 printf("%p\n", &ra); //打印出ra的地址 }
结果如下:
其中ra为a的引用,可见 a 和 ra 的地址一样,这就说明了变量与变量的引用公用的一块内存空间。
特别注意:引用类型必须和引用实体是同种类型的
引用特性
1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
例如:
void TestRef() { int a = 10; // int& ra; // 该条语句编译时会出错,因为没有初始化 int& ra = a; int& rra = a; printf("%p %p %p\n", &a, &ra, &rra); }
知道引用的特性后,我们就可以简化在C语言中一些简单函数的写法,如交换两个数,可直接传变量的引用为参数来实现,具体如下:
可见当传入的参数为变量的引用时,就可以避免在次开辟内存空间,一定程度上提高了代码运行效率。
常引用
所谓常引用就是在一个变量的引用前加一个关键字 const 来使这个引用具有常量的性质。
如下所示:
void TestConstRef() { const int a = 10; //int& ra = a; // 该语句编译时会出错,因为a为常量,而ra为变量(由&前面的类型决定,为int变量类型) const int& ra = a; // int& b = 10; // 该语句编译时会出错,b为常量 const int& b = 10; double d = 12.34; //int& rd = d; // 该语句编译时会出错,类型不同 const int& rd = d; }
再例如:
int main() { int i = 10; double d = i; //double& r=i; //这里编译器会报错,具体原因如下图示 const double& r = i; //加上const 修饰就会使引用具有常性 return 0; }
所以只有在定义引用前加上const 修饰就能使之具有常性。
另外要注意使用const引用时的权限问题,例如:
#include<iostream> using namespace std; int main() { // 使用常变量时变成常变量的别名的条件:不变或者缩小常变量的读写权限是可以的, //放大你常变量读写权限不行的 const int a = 10; // int& b = a; // 不能这样定义b,这样会使a的权限变大,编译器会报错 int c = 20; const int& d = c; // 可以这样定义,d变成的c的别名,d不能修改c,相当于把c的权限缩小 //其中c是可以改变的,但是d只能读不能写 return 0; }
如上解释一下:并不是每个别名(即引用)都跟原名字有一样的权限,具体要看怎么修饰。
使用场景
1、做参数
void Swap(int& left, int& right) { int temp = left; left = right; right = temp; }
这里提一下引用做参数的优点:
1、 传引用是为了减少传值传参时的拷贝
2、使用const修饰引用时可以保护形参不会被改变
3、const引用做参数时,即可接收变量,也可以接收常量
总的来说,函数传参如果想减少拷贝就用引用传参,如果函数中不改变这个参数最好用const 引用传参
2、做返回值
看如下栗子:
为什么打印出的 ret=7 呢?
这是因为函数的返回类型为 int& ,所以返回值 c 的类型就是 int&,而 ret 作为接收函数的返回值的量,也为 int& 型,所以在这里就可以把 ret 看做是 c 的别名,当程序来到 Add(3,4); 这条语句时,返回值 c 就变为了 7,所以此时的 ret 的值也就为7。
以上也说明了使用引用做返回值会有一定的风险性。
引用和指针的区别
最后来总结一下引用与指针的区别。
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
来看这样一段代码:
int main() { int a = 10; int& ra = a; ra = 20; int* pa = &a; *pa = 20; return 0; }
再查看其汇编代码,会发现引用与指针的实现方式是一样的。
引用与指针的不同点:
1.引用在定义时必须初始化,指针没有要求
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
3. 没有NULL引用,但有NULL指针
4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全(因为指针使用不慎就会造成野指针)
总结
加载全部内容