【C++拾遗】详解C++中的引用变量

引用变量被定义为一个变量的别名,即引用变量和其指向的变量代表同一个值,指向同一个存储单元,并且引用变量自从赋值起就已知跟着这个变量,不会再发生改变,也就是一个变量两个名字,所以更改其中的任何一个这个变量都会发生改变。

&符号可以指示变量的地址,同时它的另一个含义就是用来声明引用:

int genius;
int & me = genius;

这里的&不是地址运算符,而是类型标识符的一部分,就像int *int类型的指针一样,int &是指向int的引用。上述声明将me和genius等价,它们指向相同的值和内存单元,就是说me就是genius,而genius就是me。

引用和指针

引用和指针貌似很相像,例如:

int genius = 100;
int & me = genius;
int * myself = &genius;

这样,神奇的事情来了:

me == *myself == genius
&me == myself == &genius

引用与指针也有区别,例如必须再声明时将引用的值初始化,不能像指针一样,先声明在赋值;而且引用变量一旦赋值将不会再更改,这一点更接近于const指针:

int & me = genius;
int * const myself = &genius;

从而,me == *myself

将引用用作函数参数

按值传递与按引用传递

  • 按值传递:函数复制一份传入的值,然后对复制的数据进行操作,与被传入的数据无关
  • 按引用传递:函数直接使用传入的数据,不对其进行拷贝,修改的内容会直接体现在原数据上,这一点可以轻松地使用引用变量完成,抑或通过使用指针传递变量的地址来完成

按值传递与按引用传递

例如,完成一个交换两个变量的值的函数:

按值传递

void swapByValue(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

按引用传递:

void swapByReference(int & a, int & b)
{
    int temp = a;
    a = b;
    b = temp;
}

按地址(指针)传递:

void swapByPoint(int * a, int * b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

三种函数的调用方式:

swapByValue(intA, intB);
swapByReference(intA, intB);
swapByPoint(&intA, &intB);

可以看出,按指针传递的声明方法和调用方法与其他两种均不同,需要在函数定义时告知传入的变量时 int* 类型,在调用时传入变量的地址 &intA 才可以;按值传递和按引用传递的调用方式相同,直接将变量名传入,只有在定义函数处才可以直到两者的不同,一个是按值传递,一个指出了是按地址传递 & int

按引用传递的一个重要方面是被传入的值会被直接使用或者修改,例如:

int squareByValue(int a)
{
    a *= a;
    return a;
}

int squareByReference(int & a)
{
    a *= a;
    return a;
}

调用时会出现:

int a =2;
cout << squareByValue(a) << " = square of " << a; // 输出:4 = square of 2
cout << squareByReference(a) << " = square of " << a; // 输出:4 = square of 4

可见,按照引用传递时,被传入的变量的更改会影响到原始的变量。

将引用用于结构

声明一个结构

struct myStruct
{
    int myInt;
    double myDouble;
}

将引用用于结构

将结构的引用作为参数传递非常简单,同时需要注意的是最好使用引用作为返回值。否则的话,函数需要先将待返回的结构体赋予一个临时变量,然后将这个临时变量返回,这是非常耗费时间和空间的。所以应该像这样使用它们:

myStruct & sum(myStruct & target, const myStruct & source)
{
    target.myInt += source.myInt;
    target.myDouble += source.myDouble;
    return target;
}

调用该函数:

myStruct target = {1,2.5};
myStruct source = {2,3.8};
myStruct result;
result = sum(target, source);

对返回值使用const

如果不对返回值使用const,意味着返回值是可以被赋值的,即下边的表达式成立:

sum(target, source) = anotherStruct;

未来避免这种情况发生,可以使用const限定返回值:

const myStruct & sum(myStruct & target, const myStruct & source);

从而如下的语句都不能成立:

sum(target, source) = anotherStruct;
sum(sum(target, source), source);

因为无法将一个有const限定的变量传递给一个没有const限定的变量,但是可以将返回值赋给其他结构:

result = sum(target, source);

何时使用引用参数

使用引用参数的主要原因有两个:

  • 程序员能够修改调用函数中的数据对象
  • 通过传递引用而不是整个数据对象,可以提高程序的运行速度

当数据对象较大时(如结构和类对象),第二个原因最重要。这些也是使用指针参数的原因。这是有道理的,因为引用参数实际上是基于指针的代码的另一个接口。那么,什么时候应使用引用、什么时候应使用指针呢?什么时候应按值传递呢?下面是一些参考原则

  • 对于使用传递的值而不作修改的函数
    • 如果数据对象很小,如内置数据类型或小型结构,则按值传递
    • 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针
    • 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间。
    • 如果数据对象是类对象,则使用const引用。传递类对象参数的标准方式是按引用传递
  • 对于修改调用函数中数据的函数
    • 如果数据对象是内置数据类型,则使用指针
    • 如果数据对象是数组,则只能使用指针
    • 如果数据对象是结构,则使用引用或指针
    • 如果数据对象是类对象,则使用引用

转载请注明出处,本文永久更新链接:https://blogs.littlegenius.xin/2019/08/12/【C-温故知新】四函数/引用变量

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值