C++——引用详解

C++知识总结目录索引

1. 什么是引用

  引用不是创建一个新的变量,而是给一个已经定义的变量重新起一个别名,对引用的操作与对变量直接操作完全一样。引用的声明方法:类型标识符 &引用名=目标变量名;例如:

int main()
{
        int a = 10;
        int& b = a; //b就是a的引用

        cout << "The address of a is " << &a << endl;
        cout << "The address of b is " << &b << endl;

        return 0;
}       

运行上面代码,输出a、b的地址:

The address of a is 0xbff5b7e8
The address of b is 0xbff5b7e8

  我们发现a、b的地址是相同的,所以b不是一个新的变量,它只是变量a的一个别名。就相当于你的大名叫王铁柱,你爸妈给你去了个小名铁蛋,不管是叫王铁柱还是叫铁蛋,都是叫你。一个变量可以有多个引用,同理你同学还可能给你取了个外号叫毛蛋。

  如果这时候你们村又有个人也取名王铁柱,那别人叫王铁柱是叫你还是叫他呢?这就弄混了,所以当你取名王铁柱了,这个名字就是你的了,其他人就不能叫取这个名字了。当一个引用初始化成为一个变量的引用后,它就不能成为其它变量的引用了。

  既然我取了这个名字后别人就不能取了,那我能提前给我还未出生的娃取个好听的名字吗?先给他占着,答案是否定的,同理我们也不能创建一个引用而不给他初始化。

总结一下:

  • 引用不是创建一个新的变量,只是给一个已经存在的变量取一个别名。
  • 引用在初始化后就不能做其他变量的引用。
  • 一个变量可以有多个引用。
  • 引用必须初始化。.

2. const + 引用

  我们知道在C语言中,当const和指针结合时,会出现很多种情况,把人弄的晕头转向,那当const和引用结合时,又会擦出哪些火花呢?

int main()
{
    int a = 10;
    const int& b = a;
    a = 9; //此时a的值变成9,b的值也变成9
    b = 10; //报错,“表达式必须是可修改的左值”(此时b是被const修饰的,具备常属性,不能被修改)

    return 0;
}

  上面代码中我们给a的引用b加上了const,这时候我们可以修改a的值,但却不能动b。此时b被const修饰后已经具备了常属性,它是不能被修改的。这里我们可以从“权限”方面来理解。被来a是具有r和w权限的(既能被访问,又能修改),但它的引用b加上const以后权限被限制了,只有r权限(只读),相当于b的权限被缩小了。既然有缩小,那就有扩大了,我们能扩大变量的权限吗?

int main()
{
    const int a = 10;
    int& b = a;

    return 0;
}

  我们发现上一段代码连编都编不过,报错说“无法从:const int” 转换为 “int &”。这时候加了const的a具有了常属性,它就只有r权限了,这时候给它创建一个具有 r+w 权限的引用,相当于扩大了它的权限,系统报错,说明权限只能缩小,不能扩大。

下面再看一段代码:

int main()
{
    double a = 10.21;
    int& b = a;       //(1)
    const int& b = a; //(2)

    printf("%d", b);
    system("pause");
    return 0;
}

  代码(1),这里我们给一个double型的变量创建了一个int型引用,肯定这是编不过的,但把它改成代码(2)后,程序是可以编过的,可打印b的值时,打印出来的是10,并不是10.21。

  要解释上述情况我们得了解一下赋值和初始化。

初始化和赋值:初始化是在对象创建的同时使用初值直接填充对象的内存单元,不会有数据类型转换等中间过程,所以也就不会产生临时对象;而赋值则是对象创建好后任何时候都能调用且可多次调用的函数,由于它调用的是“=”运算符,因此可能会进行类型转换,产生临时对象。.

  这里要注意的是这个临时对象是具有常属性的,所以代码(1)无法通过(不能扩大权限),但加上const后,b也具有了常属性就没问题了。因为b根本类型还是int,所以它会截取a的整数部分,打印的就是a的整数部分。


3. 引用作形参

  要介绍这部分不得不提一个经典函数——Swap(当初学指针也是它作为例子哈)。

void Swap1(int n1, int n2)
{
    int tmp = n1;
    n1 = n2;
    n2 = tmp;
}

void Swap2(int* n1, int* n2)
{
    int tmp = *n1;
    *n1 = *n2;
    *n2 = tmp;
}

void Swap3(int& n1, int& n2)
{
    int tmp = n1;
    n1 = n2;
    n2 = tmp;
}

  Swap1我们知道是肯定没法完成交换任务的(形参只是实参的一份临时拷贝),所以便有了Swap2。虽然Swap2也会产生临时拷贝,但拷贝出来的形参指针里面存的地址和实参里面存的是同一个,相同的地址对应的是同一块空间,对其进行交换,实参的值就被改变了。现在来介绍第三种方法——传引用。

  Swap3函数把变量的引用作为形参,引用就代表变量本身,交换引用的值,就是交换变量的值,而且这种方法是不会产生临时拷贝的,略微的提高了效率。当我们希望通过形参改变实参的值的时候,传引用是一个很好的方法;但当不希望函数内改变参数x的值时怎么办?给形参加const,使用常引用传参


4. 引用作返回值

当引用作为返回值时,要分情况谈论它的优劣。

  1. 如果返回的是一个临时变量,就不要用引用作返回值。
  2. 如果返回对象出了当前函数的作用域依旧存在,尽量使用引用作为返回值,这样更高效。

情况1:临时变量在当前函数结束后就被销毁了,但通过返回的引用还是可以访问这块空间,这就属于非法访问了,这和返回临时变量的地址是一个道理。

情况2:为什么说这种情况下使用引用做返回值更优呢?因为函数返回值时会产生一个临时变量作为函数返回值的副本,而返回引用时不会产生值的副本。


5. 引用和指针的区别

  1. 引用只能在定义时初始化一次,之后不能改变指向其它变量;指针变量在初始化后也能多次赋值。
  2. 引用必须指向有效的变量,指针可以为空(正因如此,使用指针前必须判空)。
  3. sizeof指针对象和引用对象的意义不一样。sizeof指针是对象地址的大小,而sizeof引用得到的是所指向的变量的大小。
  4. 相对而言,引用比指针更安全,指针比引用更灵活也更危险。
  5. 指针和引用自增(++)自减(- -)意义不一样。
int main()
{
    int a = 10;
    int* p = &a;
    int& b = a;
    printf("before: %p, now: %p\n", p, p + 1); //指针变量+1,是加上它所指向的变量的类型大小。
    printf("before: %d, now: %d\n", b, b + 1); //引用+1,就是变量本身+1。

    //result:
    //before: 006FF7CC, now: 006FF7D0
    //before: 10, now : 11 
    return 0;
}
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值