《C++语言教程》04章 引用


一、独立引用

“引用(reference)”与指针象似但不是指针。引用主要有3种用法:①单独使用(一般称为“独立引用”),②作参数使用,③作返回值使用。从功能上来说,引用型变量又可以看着被引用变量的“别名”,这2个变量只是名称不同,变量的地址是同一个(共用体中的元素也是一样)。使用“引用”的好处主要是可以“逆向引用”。

常量也可以被引用,例如:“const int &ref = 10;”,这也是正确的,但这样定义无任何意义。定义独立引用时需要注意以下规则:

  1. 引用型变量在定义时必须初始化。
  2. 被引用的对象必须已经分配了空间,即不能为空,或空指针。
  3. 被引用的对象不能为地址,即指针变量、数组变量等不能被引用。


#include <iostream>
using namespace std;

int main( )
{
    int a ;
    int &b = a;    //b和a实际上是同一变量

    b = 100;       //b赋值为100,也就是a赋值为100
    cout << a << endl;

    //a的地址和b的地址应该是完全一样
    cout << &a << endl;
    cout << &b << endl;

    //-------▼下面代码有错,注释后才能运行▼-----------
    int x[] = {12,15,20} ;
    int &y = x;    //错误:数组、指针不能被引用

    int x1;
    int &y1;    //错误:引用时必须初始化
    y1 = x1;
    //-------▲上面代码有错,注释后才能运行▲-----------

    return 0;
}

二、函数的参数引用

许多教程在讲解参数引用时都喜欢选择交换两参数内容的swap(int &x, int &y)函数作例子,这的确很容易说明清楚,但并不能说这种用法优于指针作参数。

#include <iostream>
using namespace std;
                                                //|右边为指针作参数的代码,仅作比较用。
void swap(int &x, int &y);                      //|void swap(int *x, int *y);
                                                //|
int main ( )                                    //|
{                                               //|
    int i = 12;                                 //|
    int j = 25;                                 //|
    cout << "i=" << i << "   j=" << j << endl;  //|
                                                //|
    swap(i, j);                                 //|swap(&i, &j);
    cout << "i=" << i << "   j=" << j << endl;  //|
                                                //|
    return 0;                                   //|
}                                               //|
                                                //|
void swap(int &x, int &y)                       //|void swap(int *x, int *y)
{                                               //|{
    int t;                                      //|    int t;
                                                //|
    t = x;                                      //|    t = *x;
    x = y;                                      //|    *x = *y;
    y = t;                                      //|    *y = *x;
}                                               //|}

三、对象引用作参数

初学者可以先跳过这一节,待学完“类”之后再来看。


#include <iostream>
using namespace std;

class myclass {
    int who;
public:
    myclass(int n) {
        who = n;
        cout << "构造函数调用" << who << endl;
    }
    ~myclass() {
        cout << "析构函数调用" << who << endl;
    }
    int id() {
        return who;
    }
};

void f1(myclass o) {    //普通变量方式传递参数
    cout << "外部函数调用" << o.id() << endl;
}

void f2(myclass *o) {    //指针方式传递参数
    cout << "外部函数调用" << o->id() << endl;
}

void f3(myclass &o) {    //引用方式传递参数
    cout << "外部函数调用" << o.id() << endl;
}

int main ( ) 
{
    myclass x1(1);
    f1(x1);
    cout << "-------" << endl;

    myclass x2(2);
    f2(&x2);
    cout << "-------" << endl;

    myclass x3(3);
    f3(x3);
    cout << "-------" << endl;

    return 0;
}

从上面例子可以看出,用普通变量方式传递参数时,函数首先将参数复制一个副本,在函数体内使用的是副本。这个副本和参数自身不是同一个地址。而指针方式和引用方式并不产生副本,函数体内用的真是参数自身。需要注意的是,产生副本时调用了类的缺省“拷贝构造函数”,这个“拷贝构造函数”并不调用构造函数就产生了一个副本,有关详细内容参见后面章节。

四、作为函数返回值的引用类型

这一节仍然较深,建议初学者跳过。讲解这一节内容之前,先看下面的程序,这个程序有没有毛病?


#include <iostream>
using namespace std;

int &f();
int x;

int main ( ) 
{
    f() = 100;
    cout << x << endl;

    return 0;
}

int &f()
{
    return x;
}

许多人都认为第9句错了,少数人认为第4句可能有问题。事实上,这个程序完全正确。上面这个函数的返回值是引用类型,通过函数结果的设置反过来去改变“源头”数据,这种“逆向引用”为C++增强了很多功能,当然也有许多需要注意的地方。由于本教程面向初学者,因此到此为止,不再深入下去。