6.1 指向独立对象的引用类型
参考C++ Primer (3rd)的3.6章节
通过引用我们可以间接地操纵对象,使用方式类似于指针。但是不需要指针的语法。
引用类型由类型标识符和一个取地址操作符来定义。
1. 引用必须被初始化,不允许空引用。
int &refVal = ival;
int &refVal2;
// 错误引用必须被初始化为指向一个对象
2. 引用一旦初始化,就不能再引用其它数据。
3. 引用和被引用的变量实际上代表同一个内存的数据。
引用的所有操作都被应用在它所指的对象身上,包括取地址操作符。
本屌做过如下测试:
int ival = 111;
int *pi1 = &ival;
int &ri1 = ival;
int * const &pr1 = &ival;
cout << "int *pi1 =&ival--pi1:" << pi1 <<"--*pi1:" << *pi1 <<"--&pi1:" << &pi1<< endl;
cout << "int &ri1 = ival--ri1:"<< ri1 <<"--*ri1:(error)" << "--&ri1:" << &ri1 << endl;
cout <<"int * const &pr1 = &ival--pr1:" << pr1 <<"--*pr1:" << *pr1<< "--&pr1:" << &pr1 << endl << endl;
输出结果:
int*pi1 = &ival--pi1:0x28fee8--*pi1:111--&pi1:0x28fee4
int&ri1 = ival--ri1:111--*ri1:(error)--&ri1:0x28fee8
int *const &pr1 = &ival--pr1:0x28fee8--*pr1:111--&pr1:0x28feec
ri1是ival的引用,ri就相当于ival。对ri的所有操作都被应用在ival身上。如上:ri1指的是ival的值;&ri1指的是ival的地址。
pi1是ival的地址,*pi1指的是ival的值,&pi1指的是ival的地址的地址。
pr1引用的是指向整型变量的指针变量。也就是说pri是一个指向整型的指针变量,如果要对pri赋值的话只能赋整型变量的指针/地址。
顺便说一下:
int *pi1,int* pi1, int * pi1是等价的。也就是说“*”靠谁近或者之间有没有空格,并不影响功能。但是推荐使用int *pi1,因为考虑到一连串定义几个变量时可能出错。比如:int *pi1, *pi2, *pi3;而不是 int*pi1, pi2, pi3。
同理,“&”也是一样的。
int &ri1,int& ri1,int &ri1是等价的。也就是说“*”靠谁近或者之间有没有空格,并不影响功能。但是推荐使用int &ri1,因为考虑到一连串定义几个变量时可能出错。比如:int &ri1, &ri2, &ri3;而不是 int& ri1, ri2, ri3。
6.2 被用作函数的形式参数的引用类型
把参数声明成引用,实际上改变了缺省的按值传递参数的传递机制。在按值传递时,函
数操纵的是实参的本地拷贝。当参数是引用时,函数接收的是实参的左值而不是值的拷贝。
通常,传递的是形参的值或者地址的值。此时需要将形参的值拷贝(赋值)给实参,然后操纵实参。
当把参数声明为引用时,传递的是形参本身。此时不需要将形参的值拷贝(赋值)给实参,可以直接操纵形参。和指针类似。
比如:
inline vec3&vec3::operator+=(const vec3 &v)
{
e[0]+= v.e[0];
e[1] += v.e[1];
e[2] += v.e[2];
return *this;
}
形参v是一个vec3类型对象的引用,所以函数体内可以直接操作v对象(的成员变量/函数)
6.3 被用作函数返回的引用类型
c++函数的返回分为以下几种情况:
1)主函数main的返回值:这里提及一点,返回0表示程序运行成功。
2)返回非引用类型:函数的返回值用于初始化在跳用函数出创建的临时对象。用函数返回值初始化临时对象与用实参初始化形参的方法是一样 的。如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。且其返回值既可以是局部对象,也可以是求解表达式的结果。
3)返回引用:当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。
例如:
inline vec3& vec3::operator+=(const vec3 &v)
{
e[0] += v.e[0];
e[1] += v.e[1];
e[2] += v.e[2];
return *this;
}
测试代码如下:
vec3 v1(1.0, 2.0,3.0);
vec3 v2(4.0, 5.0,6.0);
vec3 vt;
std::cout <<"v1: " << v1.e[0] << " " << v1.e[1]<< " " << v1.e[2] << endl;
std::cout <<"v2: " << v2.e[0] << " " << v2.e[1]<< " " << v2.e[2] << endl;
vt = v1.operator+=(v2);
std::cout <<"v1====================: " << v1.e[0] << " "<< v1.e[1] << " " << v1.e[2] << endl;
std::cout <<"vt = v1.operator+=(v2): " << vt.e[0] << " "<< vt.e[1] << " " << vt.e[2] << endl;
测试结果如下:
v1: 1 2 3
v2: 4 5 6
v1====================:5 7 9
vt =v1.operator+=(v2): 5 7 9
根据函数体,operator+=()返回的调用该函数的对象的引用,此处为v1的引用。所以,将v1的应用赋值给vt就相当于将v1赋值给vt。
根据测试结果,v1,vt两个向量确实相等。
又感觉引用和指针好像哈!这样说吧,引用能干的事情,指针都能干。那么问题来了,为什么还要“引用”这东西???
网友给出一个非常好的解释:(够用,简单,可靠)
答案是“用适当的工具做恰如其分的工作”。
指针能够毫无约束地操作内存中的如何东西,尽管指针功能强大,但是非常危险。
就象一把刀,它可以用来砍树、裁纸、修指甲、理发等等,谁敢这样用?
如果的确只需要借用一下某个对象的“别名”,那么就用“引用”,而不要用“指针”,以免发生意外。比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如果把取公章的钥匙交给他,那么他就获得了不该有的权利。
http://blog.csdn.net/thisispan/article/details/7456169