C++引用
beyond.myself 人气:01.引用的概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
2.引用的格式
类型 & 引用变量名 ( 对象名 ) = 引用实体;
举例如下:
注意:引用类型必须和引用实体是同种类型的
3.引用的特性
(1). 引用在 定义时必须初始化
例如:int& d; 这样就是没有初始化是错的
(2). 一个变量可以有多个引用
int a = 10;
int& b = a;
int& c = b;
int* p = &b; //p是指针
(3). 引用一旦引用一个实体,再不能引用其他实体
4.取别名原则
对原引用变量,权限只能缩小,即 可读可写(普通类型) 可以改成 只读(const);不能放大:,即 只读 不能改成 可读可写的
例子1:权限的放大,不能把const给非const
例子2:权限的缩小 非const 既可以给非const,也可以给const:
例子3:权限缩小和放大规则:适用于引用和指针间
例子4: 权限不适用于普通赋值:
难点:隐式类型转换的引用
整形e能否做双精度浮点型d的别名呢?
直接赋值是不行的,需要加上const才正确。即:const int& e = d;
正确
解释:隐式类型转换的普通赋值的情况,上面的例子:int f=d;从语法上看把8字节的d不能直接给4字节的f,因为浮点数和整形的存储形式就不一样,没办法直接截取,所以d需要先把整数部分给一个4字节的临时变量,再把临时变量给f
再看引用:int& e=d;
临时变量具有常性,所以这里把临时变量给引用e的时候,相当于是把自带const的临时变量赋值给非const的e,把只读的给可读可写的是放大了权限,所以错误;必须改成const int& e=d;
才正确!
5.引用的使用场景
做参数
(1)传参:实参给形参传值和传地址都需要传一份值/地址的拷贝,引用传参可以减少拷贝,提高效率
void Swap(int& x, int& y) { int tmp = x; x = y; y = tmp; } void Swap(double& x, double& y) { double tmp = x; x = y; y = tmp; } int main() { int a = 0, b = 1; swap(a, b); double c = 1.1, d = 2.2; swap(c, d); return 0; }
(2)作输出型参数:
leetcode上的题往往有输出型参数,在c++中就可以用引用代替更加方便
做返回值
int&Count()的讲解
传值返回:会有一个拷贝
传引用返回:没有这个拷贝了,函数返回的直接就是返回变量的别名
int& Count() { int n = 0; n++; return n; } int main() { int ret = Count(); return 0; }
首先我们来看普通的传值返回:普通的传值返回需要把返回值n给一个函数类型int的临时变量(函数类型就是返回值类型),再把临时变量给ret。
为什么设计一个临时变量,直接把n给ret不行吗?
答:不行,因为当函数Count里执行完各种代码后,返回n,等出了Count函数的作用域后n就会销毁,所以不能直接把n给ret,需要一个临时变量。
如何证明返回时存在临时变量呢?:如果你用int& ret 接收,写成int& ret = Count();
发现无法运行,因为临时变量有常性,所以需要写成const int& ret = Count();
才能通过。
此时再看传引用返回:
当用引用接收引用返回时:这里ret和n的地址一样,也就意味着ret其实就是n的别名。但是因为n出作用域不会立即被覆盖,所以第一次通过ret可以打印是1,当打印第二次时,因为前面已经调用过一次打印函数,已 "销毁" 的Count函数栈帧在此时被打印函数覆盖,再打印ret就会是随机数了!
即:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已 经还给系统了,则必须使用传值返回。
用static修饰n后:用static静态变量使n只初始化一次且改变其生命周期,把n放进了静态区,这样n就一直存在,就可以通过ret找到n了,再怎么打印ret都是1.
传值传引用效率比较
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是 当参数或者返回值类型非常大时,效率就更低。 总结:传值和指针在作为传参以及返回值类型上效率相差很大 。
6.引用和指针的不同点
1. 引用 在定义时 必须初始化 ,指针没有要求
2. 引用 在初始化时引用一个实体后,就 不能再引用其他实体 ,而指针可以在任何时候指向任何一个同类型 实体
3. 没有 NULL 引用 ,但有 NULL 指针
4. 在 sizeof 中含义不同 : 引用 结果为 引用类型的大小 ,但 指针 始终是 地址空间所占字节个数 (32 位平台下占 4 个字节 )
5. 引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同, 指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全
引用和指针在语法上是不一样的,但是实际上从反汇编的代码上我们能看到引用和指针的底层实现是一样的!
这就好比保时捷的卡宴和大众的途锐汽车,他们的三大件底盘,发动机,变速箱都是一样的,但是他们的品牌不一样,价格不同
加载全部内容