C++之引用怎么用

Posted 两片空白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++之引用怎么用相关的知识,希望对你有一定的参考价值。

1.引用的概念

        引用并不是新定义一个变量,而是给一个已存在的变量取一个别名。编译器并不会为引用变量开辟空间,它和它应用的变量共用一块空间。也就是说引用是同一块变量空间的不同名字

        格式:类型&  引用变量名=引用实体

 注意:上面ra的类型还是整形(int),类型并不是int&,对引用进行赋值就是对他引用的实体赋值。

2.引用特性

  •  引用在定义时必须初始化。否则不知道引用的哪一个
#include<iostream>
using namespace std;

int main(){
	int a=10;
	int& ra;//编译时出错
    return 0;
}
  • 一个变量可以有多个引用。
#include<iostream>
using namespace std;
//这样都是正确的,一块空间的多个命名
int main(){
	int a=10;
	int& ra=a;
	int& rb = a;
	int& rc = ra;
    return 0;
}
  • 应用一旦引用一个实体,再也不能引用其它实体。不然就是赋值。

3.常引用

  • 一个常量的引用也应该是一个常量
#include<iostream>
#include<Windows.h>
using namespace std;

int main(){
	const int a=10;
	//int& ra=a;编译时出错
	const int& ra = a;

	system("pause");
    return 0;
}

原因:变量a是可读不可改写的,引用ra是可读可改写的,如果对ra改写,就会对a产生影响。所以会编译出错。

  • 一个变量也可以用一个常量引用来引用
#include<iostream>
#include<Windows.h>
using namespace std;

int main(){
	int a=10;
	int& ra=a;
	const int& rb = a;//可以用一个常量引用

	system("pause");
    return 0;
}

原因:变量a是可读可改写的,引用rb是可读不可改写的。这是允许的。

  • 还有一种特殊情况,当引用时发生隐式转化,用常引用接受可以。如下
#include<iostream>
#include<Windows.h>
using namespace std;

int main(){
	double a=3.14;
	//int& ra=a;//编译出错
	const int& rb = a;//正确

	system("pause");
    return 0;
}

原因:当发生隐式转化时,会产生一个临时变量,改临时变量先将原来值进行转化,再赋值给新值。重要的原因是,该临时变量具有常量性质(可读不可改写)。所以需要常引用接收。

用上面的例子就是,rb引用a时发生隐式转化,此时会创建一个临时变量tmp,先将a转化为int,再将tmp值赋给rb。

注意是引用的时候发生隐式转化时,提前隐式转化,再引用不需要常引用接收。

#include<iostream>
#include<Windows.h>
using namespace std;

int main(){
	double a=3.14;
	int c = a;//提前转化,再引用
	int& rc = c;//正确

	system("pause");
    return 0;
}

结论:引用时,读写权限可以缩小不可以放大。

4.使用场景

  • 做参数

例如一个简单的交换函数Swap,在C语言中,我们需要进行传址操作,才能实现实参数值的交换,但是在C++中,我们可以使用引用,就可以实现实参的交换。

此时是如何实现交换的呢?

可以这样理解,x是a的引用,y是b的引用,引用就是实体本身,也就是说。x就是a,y就是b,他们发生值交换就是a,b发生值交换。因为这里并没有为x和y开辟空间,形成临时变量。

  • 做返回值

这里有几点值得推敲的地方:

1.这里为什么要用static修饰n,如果不用static修饰会怎么样?

上面返回值为int&引用,在main函数中用引用a来接收。我们知道引用并不开辟空间,所以a并没有开辟空间,而是n的引用,也就是n和a的地址会相同。如果不用static修饰n,则n变量在栈上开辟空间,如果调用一个其它的函数,a的值很有可能会发生改变,这样a的值得不到保障。但是static修饰的变量在静态区存储,值并不会发生改变。如下是不用static修饰的变量:

2.返回值不是引用的,如果想用引用来接收,必须使用常引用。

#include<iostream>
#include<Windows.h>
using namespace std;

int Count(){
	int n = 0;
	n++;
	return n;
}

int main(){
	//int& a = Count();//编译错误
	const int& a = Count();//正确

	system("pause");
    return 0;
}

原因:和隐式转化差不多,当返回的时候,会生成一个临时变量,该临时变量的值等于返回值。并且,该返回值具有常量性质。

3.引用做返回值,也可以不使用引用来接收,这样值就得到了保障。

原因:此时main函数里的a开辟空间,与n无关了,或者说与返回时创建的临时变量无关了,只是将它的值赋给了a。

也可以看成下面这样。b的改变并不会影响ra,a。

#include<iostream>
#include<Windows.h>
using namespace std;

int& Count(){
	int n = 0;
	n++;
	return n;
}

int main(){
	const int a = 10;
	const int& ra = a;
	int b = ra;//此时b与ra,a无关,只是将值赋给了b

	system("pause");
    return 0;
}

总结:函数返回时都会创建一个临时变量,引用返回也会创建一个临时变量,但是这个临时变量并不开辟空间,而是返回值的一个引用。可以用引用接收(不是static修饰的值得不到保证),适用于静态和全局变量。也可以不使用引用接收,只是将值赋给了接收变量,值得到了保障。

返回值不是应用,会创建一个临时变量,会临时开辟空间,并且该临时变量具有常量性质。

5.传值和传引用,返回值和返回引用的效率说明

以值作为参数或者返回值,在传参数和返回期间,函数不会直接传递给实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时拷贝,由上可知要开辟临时空间。因此效率时很地下的,而使用引用作为参数和返回值时,并不需要开辟空间。

因此传值,返回值比传引用和返回引用的效率低。

6.引用和指针的区别

        在语法概念上,引用没有独立的空间,而是和实体公用一块空间。指针在32位机器下占4字节空间,在64位机器下占8字节空间。

        在底层实现上,引用实际时有空间的,因为引用时按照指针来实现的。

可以发现,在汇编下,引用和指针实现时一样的。

        指针与引用的不同点:

  1. 引用在概念上是定义一个变量的别名,指针存储一个变量的地址。
  2. 引用在定义时必须初始化,指针没有要求。
  3. 引用在引用一个实体后,不能再引用其它实体,指针在任何时候都可以指向一个同类型的实体。
  4. 没有NULL引用,指针可以指向NULL。
  5. 在sizeof中含义不同,引用的结果是引用类型的大小(int&类型是int)。但是指针始终是地址空间所占字节大小(在32位机器下占4字节空间,在64位机器下占8字节空间)
  6. 有多级指针,没有多级引用。
  7. 访问实体不同,指针需要显式解引用,引用编译器自己处理。
  8. 引用加1,为实体数值加1。指针加1,为加上指向类型的大小。
  9. 引用比指针使用起来相对安全。

以上是关于C++之引用怎么用的主要内容,如果未能解决你的问题,请参考以下文章

引用向量的部分片段?

C++之引用&的详解

C++之引用的详解

head标签怎么给多个html引用

C++ 解释器/控制台/片段编译器

这些 C++ 代码片段有啥作用?