当前位置:嗨网首页>书籍在线阅读

04-创建引用变量

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

8.2.1 创建引用变量

前面讲过,C和C++使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。例如,要将rodents作为rats变量的别名,可以这样做:

int rats;
int & rodents = rats; // makes rodents an alias for rats

其中,&不是地址运算符,而是类型标识符的一部分。就像声明中的char*指的是指向char的指针一样,int &指的是指向int的引用。上述引用声明允许将rats和rodents互换——它们指向相同的值和内存单元,程序清单8.2表明了这一点。

程序清单8.2 firstref.cpp

// firstref.cpp -- defining and using a reference
#include <iostream>
int main()
{
    using namespace std;
    int rats = 101;
    int & rodents = rats; // rodents is a reference
    cout << "rats = " << rats;
    cout << ", rodents = " << rodents << endl;
    rodents++;
    cout << "rats = " << rats;
    cout << ", rodents = " << rodents << endl;
// some implementations require type casting the following
// addresses to type unsigned
    cout << "rats address = " << &rats;
    cout << ", rodents address = " << &rodents << endl;
    return 0;
}

请注意,下述语句中的&运算符不是地址运算符,而是将rodents的类型声明为int &,即指向int变量的引用:

int & rodents = rats;

但下述语句中的&运算符是地址运算符,其中&rodents表示rodents引用的变量的地址:

cout <<", rodents address = " << &rodents << endl;

下面是程序清单8.2中程序的输出:

rats = 101, rodents = 101
rats = 102, rodents = 102
rats address = 0x0065fd48, rodents address = 0x0065fd48

从中可知,rats和rodents的值和地址都相同(具体的地址和显示格式随系统而异)。将rodents加1将影响这两个变量。更准确地说,rodents++操作将一个有两个名称的变量加1。(同样,虽然该示例演示了引用是如何工作的,但并没有说明引用的典型用途,即作为函数参数,具体地说是结构和对象参数,稍后将介绍这些用法)。

对于C语言用户而言,首次接触到引用时可能也会有些困惑,因为这些用户很自然地会想到指针,但它们之间还是有区别的。例如,可以创建指向rats的引用和指针:

int rats = 101;
int & rodents = rats; // rodents a reference
int * prats = &rats;  // prats a pointer

这样,表达式rodents和prats都可以同rats互换,而表达式&rodents和prats都可以同&rats互换。从这一点来说,引用看上去很像伪装表示的指针(其中,解除引用运算符被隐式理解)。实际上,引用还是不同于指针的。除了表示法不同外,还有其他的差别。例如,差别之一是,必须在声明引用时将其初始化,而不能像指针那样,先声明,再赋值:

int rat;
int & rodent;
rodent = rat; // No, you can't do this.

注意: 必须在声明引用变量时进行初始化。

引用更接近const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它。也就是说:

int & rodents = rats;

实际上是下述代码的伪装表示:

int * const pr = &rats;

其中,引用rodents扮演的角色与表达式*pr相同。

程序清单8.3演示了试图将rats变量的引用改为bunnies变量的引用时,将发生的情况。

程序清单8.3 sceref.cpp

// secref.cpp -- defining and using a reference
#include <iostream>
int main()
{
    using namespace std;
    int rats = 101;
    int & rodents = rats; // rodents is a reference
    cout << "rats = " << rats;
    cout << ", rodents = " << rodents << endl;
    cout << "rats address = " << &rats;
    cout << ", rodents address = " << &rodents << endl;
    int bunnies = 50;
    rodents = bunnies;  // can we change the reference?
    cout << "bunnies = " << bunnies;
    cout << ", rats = " << rats;
    cout << ", rodents = " << rodents << endl;
    cout << "bunnies address = " << &bunnies;
    cout << ", rodents address = " << &rodents << endl;
    return 0;
}

下面是程序清单8.3中程序的输出:

rats = 101, rodents = 101
rats address = 0x0065fd44, rodents address = 0x0065fd44
bunnies = 50, rats = 50, rodents = 50
bunnies address = 0x0065fd48, rodents address = 0x0065fd4

最初,rodents引用的是rats,但随后程序试图将rodents作为bunnies的引用:

rodents = bunnies;

咋一看,这种意图暂时是成功的,因为rodents的值从101变为了50。但仔细研究将发现,rats也变成了50,同时rats和rodents的地址相同,而该地址与bunnies的地址不同。由于rodents是rats的别名,因此上述赋值语句与下面的语句等效:

rats = bunnies;

也就是说,这意味着“将bunnies变量的值赋给rat变量”。简而言之,可以通过初始化声明来设置引用,但不能通过赋值来设置。

假设程序员试图这样做:

int rats = 101;
int * pt = &rats;
int & rodents = *pt;
int bunnies = 50;
pt = &bunnies;

将rodents初始化为*pt使得rodents指向rats。接下来将pt改为指向bunnies,并不能改变这样的事实,即rodents引用的是rats。