问题六:C++中&是干嘛用的(引用类型)

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 被用作函数的形式参数的引用类型

         参考C++ Primer(3rd)的7.3.1章节

把参数声明成引用,实际上改变了缺省的按值传递参数的传递机制。在按值传递时,函

数操纵的是实参的本地拷贝。当参数是引用时,函数接收的是实参的左值而不是值的拷贝。

         通常,传递的是形参的值或者地址的值。此时需要将形参的值拷贝(赋值)给实参,然后操纵实参。

当把参数声明为引用时,传递的是形参本身。此时不需要将形参的值拷贝(赋值)给实参,可以直接操纵形参。和指针类似。

比如:

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

 

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值