c++(7)引用作为函数的返回值、指针引用、const引用

1、引用作为函数的返回值

引用作为返回值,一般不常见,实际在真正的工作过程中也是极少遇见。引用作为返回值有他的有点,也有他

的缺点。看下面的代码

#include <iostream>
using namespace std;

//这种实现方式,在调用的时候,return p,其实还是发生了拷贝动作
char *getmem1(int size)
{
	char *p = NULL;
	p = (char *)malloc(size);
	
	if (NULL != p)
		return p;
	
	return NULL;//拷贝地址 0x11223344
}

//指针的方式
int getmem2(char **pp, int size)
{
	char *p = NULL;
	p = (char *)malloc(size);
	
	if (NULL != p)
	{
		*pp = p;
		return 0;
	}
	
	return -1;
}

//引用作为返回值,不要返回局部变量的引用(别名)、地址
int& getA()
{
	int a=10;
	return a;//int &temp = a;
}

int& getA1()
{
	static int a=10;
	return a;//int &temp = a;除非数据在静态区  这样才是可以的
}

int main(void)
{
	
	/*int main_a = 0;
	main_a = getA();//main_a = temp 这里赋值的是getA中的临时变量,而临时变量a在return的时候被销毁
	cout<<"main_a = "<<main_a<<endl;  //返回temp的别名,打印时直接奔溃
	
	int &main_a_re = getA(); //main_a_rew为a别名,一样会出问题
	cout<<"main_a_re = "<<main_a_re<<endl;  //奔溃报错*/
	
	int &main_a_re = getA1(); //main_a_rew为a别名,a在静态区,或者是在堆上申请的,是可以的。结果打印10
	cout<<"main_a_re = "<<main_a_re<<endl;  
	
	//同样的,由于getA1返回的是静态变量的别名,所以可以被赋值
	getA1() = 100;
	cout<<"main_a_re = "<<main_a_re<<endl; //结果为打印100
	
	//结论:当引用如果作为函数返回值时,不可以返回局部变量,可以返回静态变量,并可以被作为左值在进行赋值操作
	
	return 0;
}

getmem1和getmem2,是简单介绍了一下,通过指针可以实现的返回指针的操作。同理,根据上一篇的内容,能用指针实现的。使用引用也可以实现。这里不做过多研究了。

下面开始分析:当引用作为返回值,如getA,实际上返回的是一个别名,我们把getA理解是一个局部的变量temp,在函数返回的时候相当于是 int &temp = a;返回的是局部变量a的别名。

但是局部变量a在栈上,并当函数返回时被销毁。所以下面如果直接使用main_a = getA();会出现垃圾值,甚至会直接程序奔溃。

getA1也是如此,但是getA1返回的是静态变量,当函数返回时不被销毁。所以可以使用。同时由于getA1返回的是静态变量a的别名,我们还可以把它当做左值,进行赋值操作。

结论:(缺点)当引用如果作为函数返回值时,不可以返回局部变量,

(优点)可以返回静态变量,并可以被作为左值在进行赋值操作。但其实引用作为函数返回值,并不被推荐使用。

2、指针引用

指针的引用,就和正常的整形变量、或者结构体变量一样,只不过引用的对象是指针。相当于是给指针做了一个别名,常常会使用在函数的入参当中。看下面这个程序

#include <iostream>
#include <cstring>
using namespace std;

struct teacher
{
	int id;
	char name[64];
};

//指针的方式
int get_teacher(struct teacher **pp)
{
	struct teacher *pt = NULL;
	pt = (struct teacher *)malloc(sizeof(struct teacher));
	if (NULL != pt)
	{
		pt->id = 10;
		strcpy(pt->name, "zhang3");

		*pp = pt;
		return 0;
	}
	
	return -1;
}

void free_teacher(struct teacher **pp)
{
	if (NULL == pp)
		return ;
	
	struct teacher *p = *pp;
	if (p != NULL)
	{
		free(p);
		*pp = NULL;
	}
}

//引用的方式
int get_teacher1(struct teacher *&pre) //相当于struct teacher *是一个整体,pre就是入参的别名
{
	pre = (struct teacher *)malloc(sizeof(struct teacher));
	if (NULL != pre)
	{
		pre->id = 11;
		strcpy(pre->name, "li4");
		
		return 0;
	}
	
	return -1;
}

//通过引用的方式,比较简单,不会像二级指针那样,可能会使用错误。//比如我第一次写的时候就改了很多次,二级指针才用对
void free_teacher1(struct teacher *&pre)
{
	if (pre != NULL)
	{
		free(pre);
		pre = NULL;
	}
}

int main(void)
{
	
	struct teacher *pt = NULL;
	get_teacher(&pt);
	cout<<pt->name<<" "<<pt->id<<endl;
	free_teacher(&pt);
	
	get_teacher1(pt);
	cout<<pt->name<<" "<<pt->id<<endl;
	free_teacher1(pt);

	
	return 0;
}

因为入参是一个指针,所以通过get_teacher来申请堆上的空间,就需要传入二级指针。当然也可以用局部变量一级指针来malloc,最后在用一次值拷贝,不过当数据量比较大的时候,值拷贝就不能作为是一个好的方法。

get_teacher入参二级指针,在使用的时候需要对指针进行取地址,然后传入参数。很多人使用二级指针并不是很熟悉,一不小心就会出错。包括后面的free_teacher也是一样的。

通过使用引用作为入参,void free_teacher1(struct teacher *&pre)  就比较简单了,这里的pre就是指针struct teacher *入参的别名,吧struct teacher *当做是和int一样的一种数据结构、当做一个整体就很好使用了。
有点自然是,代码写起来比较简单,不容易出错。

3、const引用

const引用通常是作为形参使用,其实就在常指针的及出厂,再加一个const修饰,起到一个保护作用。

int main(void)
{
	
	const int a = 10;
	
	//int &re = a;  这样的话 在c++编译器中会直接报错,error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
	const int &re = a; //如果想对一个常量进行引用,必须是一个const引用
	
	int b=20;
	const int &re2 = b;  //这样是可以的,但是re2作为b的别名,却是一个const类型,所以re2也不可以改变。但是b可以修改。
	//re2 = 30; 使用引用的时候实际上就是加了一个取值符号  *re2,理解
    b = 30; 


	
	return 0;
}

a. 常量引用 : 将引用绑定到const对象上(其实就是对const的引用)。

b. 常量引用表示不能通过引用改变绑定对象的值,但是对象的值可以通过别的方式改变。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值