订单查询 购书指南 购物车 收藏  
    首页 热点专题 精确搜索 精品推荐 俱乐部论坛 下载服务 走近科海 征稿专栏 新书预告 各地经销商 特价直销


Chapter 8 函数,第二部分:引用,重载和默认参数

深入
    声明引用参数 当Bjarne Stroustrup在1986年写The C++ Programming Language(在书中他第一次描述了C++)一书时,他介绍了一种声明引用参数的格式,其他一些程序员也采用了这种格式。在这种格式中,&是和类型名而不是变量名放在一起的。例如,下面是声明函数swap()原型的另一种方法:
void swap(int& x, int& y);
    你可以看到,&是与类型名int而不是变量名x相邻的。 另外,一些程序员在声明指针时,也把*与类型名相连而不是与变量名相连,如下所示:
float* p;
    这种声明反映出,一些程序员希望C++能包含一个独立的引用类型或者指针类型。但是,将&或*与类型相连而不是和变量相连会产生一个问题,根据正式的C++语法,&和*都不能作用于一组变量,所以这会产生令人迷惑的声明。例如,下面的声明创建了一个(而不是两个)整型指针:
int* a, b;
    在上面的代码中,b被声明为整数(而不是指向整数的指针),因为C++语法规定,在声明变量时,*和&都是作用于紧跟其后的变量,而不是变量类型。    
    有一点很重要,就C++编译器而言,无论你写成int *p或int* p都无关紧要。也就是说,如果你更愿意将*或&与类型相连而不是与变量相连,也是可以的。但是,为了避免产生混淆,本书将继续把*和&与它们所修饰的变量名连在一起。
    提示:C不支持引用。也就是说,在C中创建引用调用的惟一方法是使用指针,在函数swap()第一个版本中使用的就是这种方法。当把C代码转换为C++代码时,你要尽可能地将这种参数转换为引用参数。

8.2.1 返回引用

    函数可以返回引用。在C++程序设计中,有几种返回引用值的用法。在本书后面学习到运算符重载时你将会看到这样的用法。然而,返回引用还有其他重要的应用,现在你就会使用到这些应用。
    当函数返回引用时,它返回的是一个指向返回值的隐式指针。这带来了一种可能性:函数可以被放在赋值语句的左边!例如下面这个简单的程序:
 //返回一个引用
 #include <iostream>
 using namespace std;
 double &f();
 double val = 100.0;
 int main()
 {
 double newval;
 cout << f() << '\n'; //输出val的值
 newval = f(); //将val的值赋给newval
 cout << newval << '\n'; //输出newval的值
 f() = 99.1; //改变val的值
 cout << f() << '\n'; //显示 val的新值
 return 0;
 }
 double &f()
 {
 return val; //返回一个指向val的引用
 }
 函数输出如下:
 100
 100
 99.1
    让我们来仔细研究这个程序。在开始,f()被声明为返回一个double类型的引用,全局变量val被初始化为100。接下来,下面的语句将输出val的初始值:
 cout << f() << '\n'; //输出val的值
    当调用f()时,函数将返回一个指向val的引用。因为f()被声明为返回引用,所以下面这行语句:
 return val; //返回一个指向val的引用
    将自动地返回一个指向val的引用。这个引用然后被cout语句用来输出val的值。
    在下面这行语句:
 newval = f(); //将val的值赋给newval
    由f()返回的指向val的引用被用来将val的值赋给newval。
    在该程序中我们最感兴趣的是下面这行语句: f() = 99.1; //改变val的值 这条语句使得val的值被变成99.1。原因如下:由于f()返回的是val的引用,而该引用则成为赋值语句的目标变量。因此,99.1通过由f()所返回的引用被间接地赋给了val。
    最后,在下面这行语句中:
 cout << f() << '\n'; //输出val的新值
    当在cout语句中使用了由f()返回的val引用时,val的新值就被输出。
    下面是使用返回引用类型的另一个示例:
 #include <iostream>
 using namespace std;
 double &change_it(int i); //返回一个引用
 double vals[] = {1.1, 2.2, 3.3, 4.4, 5.5};
 int main()
 {
 int i;
 cout << "Here are the original values: ";
 for(i=0; i<5; i++)
 cout << vals[i] << ' ';
 cout << '\n';
 change_it(1) = 5298.23; //改变第2个元素的值
 change_it(3) = -98.8; //改变第4个元素的值
 cout << "Here are the changed values: ";
 for(i=0; i<5; i++)
 cout << vals[i] << ' ';
 cout << '\n'; return 0;
 }
 double &change_it(int i)
 {
 return vals[i]; //返回一个对第i个元素的引用
 }
    该程序改变了vals数组中第二个和第四个元素的值。
    程序输出如下:
    Here are the original values: 1.1 2.2 3.3 4.4 5.5
    Here are the changed values: 1.1 5298.23 3.3 -98.8 5.5
    让我们来看看这是如何实现的。函数change_it()被声明为返回double类型的引用,该函数返回的是一个由其参数i指定的数组vals中元素的引用。因此,在main()中,当下面的语句被执行时:
 change_it(1) = 5298.23; //改变第2个元素的值
    change_it()返回的是对vals[1]的引用。通过这个引用,vals[1]被赋值为5298.23。当下面的语句被执行时,同样,vals[3]被赋值为-98.8:
 change_it(3) = -98.8; //改变第4个元素的值
    因为change_it()返回的是数组vals中特定元素的引用,所以该函数可以放在赋值语句的左边用来对这个数组元素进行赋值。 当函数返回一个引用时,要注意被引用的对象不能超出作用域,例如下面这个函数:
 //错误, 不能返回对局部变量的引用。
 int &f()
 {
 int i=10;
 return i;
 }
    在上述代码中,当函数f()返回时,局部变量i将超出作用域。因此,由f()返回的对i的引用将是未定义的引用。事实上,一些编译器正是因为这个原因,在编译f()函数时认为它是不可写的(也就是不能放在赋值语句的左边)。此外,这类问题也可能会间接产生,所以当你返回对一个对象的引用时,要仔细检查这个对象是否会超出作用域。
上一页   下一页
本书前言 本书目录 返回专题首页