C++ 笔记(15)— 引用(声明引用、引用作为参数、引用作为函数返回值、const 用于引用)

引用是变量的别名。也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

1. 创建引用

要声明引用,可使用引用运算符 & ,如下面的语句所示:

VarType original = Value;
VarType& ReferenceVariable = original;

有如下变量

int i = 0;

我们可以为 i 声明引用变量,如下所示:

int&  r = i;
double& s = d;

在这些声明中, & 读作引用。因此,第一个声明可以读作 r 是一个初始化为 i 的整型引用,第二个声明可以读作 s 是一个初始化为 ddouble 型引用。下面的实例使用了 int 和 double 引用:

#include <iostream>
using namespace std;
 
int main ()
{
    // 声明简单的变量
    int    i;
    double d;

    // 声明引用变量
    int&    r = i;
    double& s = d;

    int& r2 = r;

    i = 5;
    cout << "Value of i : " << i << endl;
    cout << "Address of i : " << &i << endl;
    cout << "Value of i reference r : " << r  << endl;
    cout << "Address of i reference  r&: " << &r  << endl;
    cout << "Address of i reference r2&: " << &r2  << endl;
    cout << "Value of i reference r : " << r  << endl;
    d = 11.7;
    cout << "Value of d : " << d << endl;
    cout << "Value of d reference : " << s  << endl;

    return 0;
}

输出结果:

Value of i : 5
Address of i : 0x7ffe2bf65734
Value of i reference r : 5
Address of i reference  r&: 0x7ffe2bf65734
Address of i reference r2&: 0x7ffe2bf65734
Value of i reference r : 5
Value of d : 11.7
Value of d reference : 11.7

其中 r2 是 r 的引用,而 r 又是 i 的引用,所以 r2、r、i 的内存地址是相同的。

2. 引用和指针的区别

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

3. 引用的特点

典型的函数声明类似于下面这样:

ReturnType DoSomething(Type parameter);

调用函数 DoSomething( ) 的代码类似于下面这样:

ReturnType Result = DoSomething(argument); // function call

上述代码导致将 argument 的值复制给 parameter,再被函数 DoSomething( ) 使用。如果 argument 占用了大量内存,这个复制步骤的开销将很大。同样,当 DoSomething( ) 返回值时,这个值被复制给 Result。如果能避免这些复制步骤,让函数直接使用调用者栈中的数据就太好了。为此,可使用引用。

可避免复制步骤的函数版本类似于下面这样:

ReturnType DoSomething(Type& parameter); // note the reference&

调用该函数的代码类似于下面这样:

ReturnType Result = DoSomething(argument);

由于 argument 是按引用传递的,parameter 不再是 argument 的拷贝,而是它的别名。

#include <iostream>
using namespace std;

void getSequare(int& a);

int main ()
{
    int a = 10;
    cout << "&a   is " << &a << endl;

    getSequare(a);
    cout << "&a   is " << &a << endl;
    cout << "a sequare is " << a << endl;
    return 0;
}

void getSequare(int& num)
{
    cout << "&num is " << &num << endl;
    num *= num;
}

输出结果:

&a   is 0x7ffdcf10a7a4
&num is 0x7ffdcf10a7a4
&a is 0x7ffdcf10a7a4
a sequare is 100

函数 getSequare 通过引用参数接受一个要计算其平方的数字,并通过该参数返回结果。如果忘记将参数 num 声明为引用 & ,结果将无法返回到调用函数 main() ,因为 getSequare() 将使用 num 的本地拷贝执行运算,而函数结束时该拷贝将被销毁。通过使用引用,可确保 getSequare()main() 中定义的 num 所在的内存单元进行操作。这样,函数getSequare()执行完毕后,也可以在 main() 中使用运算结果。

4. const 用于引用

可能需要禁止通过引用修改它指向的变量的值,为此可在声明引用时使用关键字 const

int original = 30;
const int& constRef = original;
constRef = 40; // Not allowed: constRef can’t change value in original
int& ref2 = constRef; // Not allowed: ref2 is not const

5. 引用作为参数传递给函数

#include <iostream>
using namespace std;

void getSequare(const int& a, int& result);

int main ()
{
    int a = 10;
    int sequare = 0;

    getSequare(a, sequare);
    cout << "sequare is " << sequare << endl;	// sequare is 100
    return 0;
}

void getSequare(const int& num, int& result)
{
    result = num * num;
}

在前一个程序中,使用同一个参数来接受输入和存储结果,但这里使用了两个参数,一个用于接受输入,另一个用于存储运算结果。为禁止修改传入的值,必须使用关键字 const 将其声明为 const 引用,如第 4 行所示。这让 a 变为其值不能修改的参数。

C++ 函数传参:
(1) 将变量名作为实参和形参。这时传给形参的是变量的值,传递是单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。// 同 c
(2) 传递变量的指针。形参是指针变量,实参是一个变量的地址,调用函数时,形参(指针变量)指向实参变量单元。这种通过形参指针可以改变实参的值。// 同 c
(3) C++提供了 传递变量的引用。形参是引用变量,和实参是一个变量,调用函数时,形参(引用变量)指向实参变量单元。这种通过形参引用可以改变实参的值。

引用和指针也很像,它们都不会创建副本,因此效率都很高。它们的主要区别在于:

  • 选择成员的时候,引用使用点 . 来查找,而指针则使用 -> 来查找。
  • 指针可能传递一个 NULL 过来,因此在使用前必须检查有效性;引用则必然代表某个对象,不需要做此检查。

6. 引用作为函数返回值

当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。

#include <iostream>
using namespace std;

int& getValue();

int main ()
{   
    int& a = getValue();
    cout << "a is " << a << endl;
    return 0;
}

int& getValue()
{
    static int ret = 100;
    return ret;
}

(1)以引用返回函数值,定义函数时需要在函数名前加 &
(2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本

其它示例代码:

double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues( int i )
{
  return vals[i];   // 返回第 i 个元素的引用
}
 
// 要调用上面定义函数的主函数
int main ()
{
 
   cout << "改变前的值" << endl;
   for ( int i = 0; i < 5; i++ )
   {
       cout << "vals[" << i << "] = ";
       cout << vals[i] << endl;
   }
 
   setValues(1) = 20.23; // 改变第 2 个元素
   setValues(3) = 70.8;  // 改变第 4 个元素
 
   cout << "改变后的值" << endl;
   for ( int i = 0; i < 5; i++ )
   {
       cout << "vals[" << i << "] = ";
       cout << vals[i] << endl;
   }
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wohu007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值