【C++学习笔记】01-理解const引用传递

第一次看到C++中的const引用传递有点困惑。在我的理解中,之所以用引用传递,是因为函数可以修改传递的参数。而不是像值传递那样,只创建参数的副本,无法修改参数。但是加上const,又表示不能修改该参数。那这const引用传递有啥用呢?

先不讨论引用传递和值传递。直接默认使用引用传递,看非const引用传递和const引用传递的区别。

实际例子

考虑如下代码

#include<iostream>  
using namespace std;  

int fun1(int& pi)
{
    cout<<"pi:"<<pi<<endl;
    cout<<"pi地址:"<<&pi<<endl;
    cout<<endl;
    return pi;
}

int fun2(const int& pi)
{
    cout<<"pi:"<<pi<<endl;
    cout<<"pi地址:"<<&pi<<endl;
    cout<<endl;
    return pi;
}

int main()  
{  
    int val_i = 3;
    double val_d = 3.14;
    
    cout<<"val_i地址:"<<&val_i<<endl;
    fun1(val_i);
    cout<<"val_d地址:"<<&val_d<<endl;
    fun1(val_d);
    fun1(3);
    fun1(3.14);

    // cout<<"val_i地址:"<<&val_i<<endl;
    // fun2(val_i);
    // cout<<"val_d地址:"<<&val_d<<endl;
    // fun2(val_d);
    // fun2(3);
    // fun2(3.14);
    return 0;
}  

这里定义了两个函数fun1和fun2,分别是非const值传递和const值传递。

先测试fun1,编译

g++ -o main main.cc -std=c++11

编译将报错:

main.cc: In function ‘int main()’:
main.cc:31:15: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
     fun1(val_d);
               ^
main.cc:8:5: note:   initializing argument 1 of ‘int fun1(int&)’
 int fun1(int& pi)
     ^
main.cc:32:11: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
     fun1(3);
           ^
main.cc:8:5: note:   initializing argument 1 of ‘int fun1(int&)’
 int fun1(int& pi)
     ^
main.cc:33:14: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
     fun1(3.14);
              ^
main.cc:8:5: note:   initializing argument 1 of ‘int fun1(int&)’
 int fun1(int& pi)

意思是用int型右值初始化非const引用是无效的。这是因为,C++中非const的引用参数必须用与其类型一致的对象/量来初始化,所以传递double变量是错误的。数字3是一个字面值,也就是个右值,而函数要求的是一个具体的int类型的对象/变量,需要左值,所以传递3也是错误的。只有第1个调用正确。

const引用传递可以完美解决上面问题。它可以在某些情况下生成临时变量,比如下面两种情况:
1、实参类型不正确,但可以转换为正确类型;
2、实参类型正确,但不是左值。

把上面代码改为用fun2,则编译通过,执行结果如下:

val_i地址:0x7ffff930ca68
pi:3
pi地址:0x7ffff930ca68

val_d地址:0x7ffff930ca70
pi:3
pi地址:0x7ffff930ca6c

pi:3
pi地址:0x7ffff930ca6c

pi:3
pi地址:0x7ffff930ca6c

可以看到,在传递val_d前后数据地址不同。这正是由于数据类型不匹配,创建了临时变量。

const引用传递的作用

在c++中当函数参数为引用时,如果传递的实参与函数参数类型不匹配,那么就要将参数类型定义为const,此时函数将会产生一个临时变量,临时变量自动转化为函数参数类型。否者将报错。

如果传递的实参是一个临时变量,那么就要将函数参数定义为const类型。否则也会报错。

即使为了代码易读,可以保证绝对不会出现字面值,有时也不得不用const引用传递。如果你写了个函数为了保护参数加了const,但函数里面调用了另一个参数没const的函数,那么这里估计就要出错,因为const实参不能传递给非const形参。虽然你能保证自己的代码不冲突,但不能保证别人的代码,尤其是合作的时候每人写一个部分。

非要用引用传递吗?

引用传递一般用于修改传递的实参,那如果不需要修改时,一律用值传递是否可以?答案是有时还真不行。原因如下:

  • 引用传递可减少类的构造和析构次数,减少程序开销。
  • 引用传递可以避免类继承时的截断问题,确保多态性。

详见下一篇文章。

小结

不需要改动的参数,如果要通过引用传递,全都加上const最安全。

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值