c++——引用(语法、引用特性、常引用、函数返回值引用和指针与引用的不同点)

c++中的引用

一、引用

1、引用的概念:给变量取别名。

形式:原类型名& 别名 = 引用实体旧名;

2、特性:

①引用定义时必须初始化
②引用一旦初始化之后就不能再改变引用的指向
③不能引用NULL
④&再等号的左边为引用,在等号的右边为取地址

引用在定义时必须初始化。否则不知道引用的哪一个

#include <iostream>
using namespace std;
int main(){
    
    
	int a=10;
	int& ra;//编译时出错
    int& r = a;
    return 0;
}

引用一旦引用一个实体,再也不能引用其它实体。不然就是赋值。

#include <iostream>
using namespace std;
int main(){
    
    
	int a=10;
    int b=20;
	int& ra=a;
	ra =b;//赋值 //ra是前面引用a的,ra再次引用就是等于赋值了
    return 0;
}

3.常引用

①一个常量的引用也应该是一个常量

#include <iostream>
using namespace std;
int main(){
    
    
	const int a=10;//const修饰定义的常量
	//int& ra=a;编译时出错
	const int& ra = a;
	system("pause");  
    int i =10;
    const int &r_i = i;
return 0;

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

②一个变量也可以用一个常量引用来引用

#include <iostream>
using namespace std;
int main(){
    
    
	int a=10;
	int& ra=a;
	const int& rb = a;//可以用一个常量rb来引用
return 0;

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

还有一种特殊情况,当引用时发生隐式转化,用常引用接收可以。
如下:

#include <iostream>
using namespace std;
int main(){
    
    
	double a=3.14;
	//int& ra=a;//编译出错
	const int& rb = a;//正确
return 0;
}

原因: 当发生隐式转化时,会产生一个临时变量,改临时变量先将原来值进行转化,再赋值给新值。重要的原因是,该临时变量具有常量性质(可读不可改写)。所以需要常引用接收。
用上面的例子就是,rb引用a时发生隐式转化,此时会创建一个临时变量tmp,先将a转化为int,再将tmp值赋给rb。
在这里插入图片描述

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

#include <iostream>
using namespace std;
int main(){
    
    
	double a=3.14;
	int c = a;//提前转化,再引用
	int& rc = c;//正确
return 0;
}

4、一个变量可以有多个引用。

#include <iostream>
using namespace std;
//这样都是正确的,一块空间的多个命名
int main(){
    
    
	int a=10;
	int& ra=a;
	int& rb = a;
	int& rc = ra;
    return 0;
}

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

5、引用场景

①引用变量

int a = 10;
int& b = a;//给a取别名为b
b = 100;
int& ra=a;
int& rb = a;
int& rc = ra;
cout << "a == " << a << endl;

一个变量可以有多个引用

②引用数组

int a[4] = {
    
    1,2,3,4};
int (&arr)[4] = a;

6、在函数中的引用

①做形参

#include <iostream>
using namespace std;
void swap(int& a,int& b){
    
    
    int temp=a;
    a=b;
    b=temp;
}
int main()
{
    
    
    int x=10;
    int y=20;
    swap(x,y);
    return 0;
}

②做返回值

#include <iostream>
using namespace std;
int& count(){
    
    
    static int n=0;
    n++return n;
}
int main()
{
    
    
    int& a=count();
    cout<<a<<endl;
    return 0;
}

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

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

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

#include<iostream>
using namespace std;
int count(){
    
    
	int n = 0;
	n++;
	return n;
}
int main(){
    
    
	//int& a = count();//编译错误
	const int& a = count();//正确
return 0;
}

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

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

#include<iostream>
using namespace std;
int count(){
    
    
	int n = 0;
	n++;
	return n;
}
int main()
{
    
    
    int a = count();
    return 0;
}

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

二、引用的效率

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

三、指针与引用的不同点

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

猜你喜欢

转载自blog.csdn.net/qq_57737603/article/details/132331654