深入c++中引用的使用

首先要强调引用和指针的区别,指针开空间存储数据的地址,自己本身也有地址,而引用是没有的

int a=0;
int&b=a;
//a和b的地址一样!
int a=0;
int*b=&a;
//a和b的地址不一样!

引用可以使用在函数传值上,这样就不用指针开辟额外空间了,这样运行时间也会减少,效率增加

#include<iostream>
using namespace std;
void my_swap(int&a,int&b){
  int tmp=a;
  a=b;
  b=tmp;
}
int main(){
  int a=1;
  int b=0;
  my_swap(a,b);
  cout<<a<<" "<<b<<endl;
  return 0;
}//输出0,1

然后具体看一下引用在返回值上的应用

先看个神奇的例子

#include<iostream>
using namespace std;
int& count(int x){
	int n=x;
	n++;
	return n;
}
int main(){
	int&ret=count(10);
	cout<<ret<<endl;//输出11
	count(20);
	cout<<ret<<endl;//输出21
	return 0;
}

加一行代码

#include<iostream>
using namespace std;
int& count(int x){
	int n=x;
	n++;
	return n;
}
int main(){
	int&ret=count(10);
	cout<<ret<<endl;
	count(20);
    printf("ss\n");
	cout<<ret<<endl;//输出一个随机数
	return 0;
}

这里第一张图是因为栈帧还没被清理(销毁),之前的内容还在,所以临时变量n还在。这里函数返回的是n的引用,ret是n的引用的引用,类似于下面这图

int a=0;
int&b=a;
int&c=b;
这里ret和c一样,n和a一样

当然,这里进行一个简单的static处理就可以变正确

#include<iostream>
using namespace std;
int& count(int x){
	static int n=x;
	n++;
	return n;
}
int main(){
	int&ret=count(10);
	cout<<ret<<endl;//输出11
	count(20);
	cout<<ret<<endl;//输出12
	return 0;
}

再看点引用在返回值上的正确使用的例子(具体应用中也经常使用,在使用结构体时非常方便),因为结构体变量和上述的static效果是一样的,即使出了要去改变结构体变量的函数,变量本身也不会销毁,因此可以直接引用,并且直接改变它,作出必要的操作

#include<iostream>
#include<assert.h>
using namespace std;
struct SeqList
{
	int a[100];
	size_t size;
};
int& SLAt(SeqList& s, int pos)
{
	assert(pos < 100 && pos >= 0);
	return s.a[pos];
}
int main(){
	SeqList s;
	SLAt(s, 0) = 1;
	cout << SLAt(s, 0) << endl;//输出1
	SLAt(s, 0) += 5;
	cout << SLAt(s, 0) << endl;//输出6
    return 0;
}

还有更好的写法,把改变结构体变量的函数放在结构体里面,再加个迭代器,当然这是c++的类独有的效果,c的结构体是没有的

#include<iostream>
#include<assert.h>
using namespace std;
struct SeqList
{
	int a[100];
	size_t size;

	int& at(int pos)
	{
		assert(pos >= 0 && pos < 100);
		return a[pos];
	}

    int& operator[](int pos)
	{
		assert(pos >= 0 && pos < 100);
		return a[pos];
	}
};
int main()
{
	SeqList s;
	s.at(0) = 0;
	s.at(0)++;
	cout << s.at(0) << endl;//输出1
	s[1] = 10;
	s[1]++;
	cout << s[1] << endl;//输出11
    return 0;
}

引用还有一个重要的特性就是它的权限只能平移或者缩小,不能扩大

int main()
{
	// 不可以
	// 引用过程中,权限不能放大
	const int a = 0;
	int& b = a;//报错
------------------------
	// 可以,c拷贝给d,没有放大权限,因为d的改变不影响c,这里只是赋值
	const int c = 0;
	int d = c;
---------------------
	// 可以
	// 引用过程中,权限可以平移或者缩小
	int x = 0;
	int& y = x;
	const int& z = x;
	++x;
	++z;//注意是const,值不能改变,报错
    //可以
    //这里是权限平移
    const int&m=10;
}

说下一般的的权限缩小

double x=1.1;
int a=x;

这里是明显的权限缩小,实际过程是先创造出一个x的int型临时变量,不改变x本身,然后再传给a。

好的,再回来看一下引用

double x=1.1;
int&a=x;//报错
const int&b=x;//编译通过

这里创造出一个x的int型临时变量,而临时变量具有常性,本身就是相当于有个const的属性,如果这里引用不加const修饰就是权限扩大,这是不被允许的,函数返回的时候也是一样,如果是返回值的话先创建一个临时变量再返回,如果是返回引用,比如返回n的引用,那么先创建临时变量int&a=n,再用int&ret=a接收

int func1()
{
	static int x = 0;
	return x;
}

int& func2()
{
	static int x = 0;
	return x;
}

int main()
{
//int& ret1 = func1();  // 权限放大
//const int& ret1 = func1(); // 权限平移
//int ret1 = func1();  // 拷贝
//
//int& ret2 = func2();		// 权限平移
//const int& rret2 = func2();  // 权限缩小
return 0;
}

又比如

int i=1;
double j=1.1;
if(j>i)cout<<"666"<<endl;
//这里比较是先创建一个i的double型临时变量,,不改变i本身

下面讲一下auto,它可以自动推导对象类型

int x=0;
auto c=x;

通常在for中使用,c++11中的for多了一种新的写法,如下所示,用引用的话还可以修改值

vector<int>res{1,2,3};
for(auto k:res){
  k++;
}
for(auto k:res){
  cout<<k<<endl;
}
//输出1,2,3
for(auto&k:res){
  k++;
}
for(auto k:res){
  cout<<k<<endl;
}//输出2,3,4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值