首页 > 编程笔记 > C++笔记 阅读:53

C++中的引用(附带实例)

C++ 11标准中提出了引用的概念,如果不加特殊声明,一般都是指左值引用。

引用实际上是一种隐式指针,它为对象建立了一个别名,通过操作符“&”来实现。其定义形式如下:
数据类型 & 表达式;

例如,下述定义了一个引用变量 ia,它是变量 a 的别名,对 ia 的操作与对 a 的操作完全一样:
int a=10;                  //定义整型变量a
int & ia=a;                //定义引用变量ia,它是a的别名
ia=2;                      //把2赋给ia,也就是a

有关引用的说明如下:
1) 一个 C++ 引用被初始化后,无法再使用它去引用另一个对象,即引用不能被重新约束。

2) 引用变量只是其他对象的别名,操作它与操作原对象的效果完全相同。

3) 指针变量与引用变量的区别为:指针是一种数据类型,引用不是数据类型;引用和变量的数据类型必须相同,不能进行类型转换;指针和引用都可以指向其他变量,指针的语法更复杂,而引用的使用方法与普通变量相同。

4) 引用必须进行初始化,否则会系统报错。例如,下面的代码会提示 references must be initialized 错误,无法通过编译:
int b;
int &a;   //未初始化的引用,无法通过编译,系统会报错

【实例 1】利用引用输出变量的值。具体代码如下:
#include <iostream>
using namespace std;
int main()
{
    int a;
    int & ref_a =a;        //定义引用变量 ref_a,它是 a 的别名
    a=100;
    cout << "a="<< a <<endl;
    cout << "ref_a="<< ref_a << endl;
    a=2;
    cout << "a="<< a <<endl;
    cout << "ref_a="<< ref_a << endl;
    int b=20;
    ref_a=b;               //改变 ref_a
    cout << "a="<< a <<endl;
    cout << "ref_a="<< ref_a << endl;
    ref_a--;
    cout << "a="<< a <<endl;
    cout << "ref_a="<< ref_a << endl;
}
程序运行结果为:

a=100
ref_a=100
a=2
ref_a=2
a=20
ref_a=20
a=19
ref_a=19

C++11右值引用

右值引用是 C++ 11 中引入的新特性,其定义形式如下:
类型 && i = 被引用的对象;

左值与右值的区别在于,右值是临时变量,如函数的返回值,并且无法改变。例如:
#include <iostream>
int get()
{
    int i =4;
    return i;
}
int main()
{
    int k =3;
    int& a =++(get());       //编译出错
    int& a =++(get())+k;     //编译出错
    return 0;
}

右值引用可以理解为对右值的引用,当右值引用初始化后,临时变量消失。例如:
#include <iostream>
int get()
{
    int i = 4;
    return i;
}
int main()
{
    int && k = get()+4;
    // int & i = get()+4;   //出错
    k++;
    std::cout<<"k的值"<<k<<std::endl;
    return 0;
}
程序运行结果为:

k的值9


右值引用只可以初始化于右值,但右值引用实质上是一个左值,它具有临时变量的数据类型。与左值引用相同的是:

C++使用引用传递函数参数

C++ 中,函数参数的传递方式主要有两种,值传递和引用传递。使用引用传递时,在调用函数中修改参数的值,其改变会影响到实际参数。

【实例 2】引用传递交换数值。定义 swap() 函数,参数为两个引用变量。主函数中输入两个值,调用 swap() 函数交换两个数值。代码如下:
#include <iostream>
using namespace std;
void swap(int & a,int & b)     //定义 swap()函数,参数为两个引用
{
    int tmp;
    tmp=a;
    a=b;
    b=tmp;
}
int main()
{
    int x,y;
    cout << "请输入x" << endl;
    cin >> x;
    cout << "请输入y" << endl;
    cin >> y;
    cout<<"通过引用交换 x 和 y"<<endl;
    swap(x,y);               //调用 swap()函数,实现两个数的交换
    cout << "x="<< x <<endl;
    cout << "y="<< y <<endl;
}
程序运行结果为:

请输入x
37
请输入y
9
通过引用交换 x 和 y
x=9
y=37

读者可以将本例与实例 1进行对比,会发现使用引用和使用指针传递参数的执行效果相同。这是因为引用本质上是一个隐式指针,而不是一个普通变量。

使用引用和指针作为函数参数,各有益处。引用必须被初始化为一个对象,且无法再指向其他对象,优点是函数中不用验证引用参数的合法性。

例如,下面的函数调用是非法的:
void ValuePass(int & var)   //定义函数 ValuePass(),使用引用作为参数
{
    var = 10;               //修改参数的值
    cout << var << endl;    //输出参数
}
int main(int argc, char *argv[])
{
    ValuePass(0);          //非法的函数调用
    return 0;
}
程序中,如果 ValuePass 采用指针作为函数参数,则“ValuePass(0);”调用语句是合法的,但存在一定的隐患。这是因为 0 会被认为是空指针,而对空指针进行操作会导致地址访问错误。

因此,当指针作为函数参数时,函数体中通常需要验证指针参数是否为空。优点是用户可以随意修改指针参数指向的对象,这是引用参数所不具备的。

相关文章