C++引用总结

10 篇文章 0 订阅

引用:

  • C++新增了一种复合类型——引用变量。引用是已定义的变量的别名,新名字与旧名字有相同的值和内存地址。
    #####创建引用变量
  • 创建引用格式:type &new_varname = old_var;(调用引用必须要初始化)
int old;
int &newname;
newname = old;//这种方式是不行的
  • 引用不光可以引用标识符(变量等),也可以引用立即数(右值、字面值、常量),但必须要加const(例如:int const &var = 40;),即常量引用。
  • 引用是一次性的,一旦与某个变量关联起来,就将一直效忠于它,无法再次更改。

看个例子

 int rats = 101;
 int* p = &rats;
 int &rodent = *p;
 int bunnies = 50;
 p = &bunnies;
 cout << rodent << endl;

程序运行结果为101,说明rodent引用的是rats。(*p为rats所在的内存地址的内容,引用*p即引用rats),若要引用指针则要这样定义:int* &rodent = p;

  • 不能空引用,引用使用不当会产生野引用(悬空引用)。
  • 引用可以当做函数的参数,它引用的对象就是函数的实参(函数将可以使用原始数据,而不是数据值的拷贝),这种传递参数的方法被称为引用传递
      优点:
        a.函数之间可以共享参数
        b.提高参数的传递效率(比指针还要高)
        c.可以获取并修改参数

为了更好的比较,下面通过一个常见的问题——交换两个变量的值,对使用引用、指针和值传递做一下比较。跳转代码

引用的属性和特别之处
#include <iostream>
//计算参数的立方
double cube(double a)//值传递
{
	a* = a*a;
	return a;
}

double refcube(double &ra)//引用传递
{
	ra *= ra* ra;
	return ra;
}

int main()
{
	using namespace std;
	double x = 3.0;
	cout << cube(x) << " = cube of " << x << endl;
	cout << refcube(x) << " = cube of " << x << endl;
	return 0;
}

我们知道,refcube()是一个引用传递的函数,那么计算立方后,x经过引用传递应该也会变成27,可是结果却是:
这里写图片描述
其实这不是因为引用传递失败了,造成这样的原因是由于cout的特性:参数从右到左入栈,即x还在x=3时就先入栈了。
  回到引用,实际上refcube函数使得x的值变成了27,如果程序员的意图是让函数使用传递给它的信息,而不对这些信息进行修改,同时又想使用引用,则应该使用常量引用,即函数应该定义为:

double refcube(const double &ra) 
{
	...
	//但此时不能再修改ra的值,ra是一个只读形参
}

所以,如果要编写类似上述类型的代码(即使用基本数据类型),应采用值传递的方式。当数据比较大(如结构和类)时,引用参数将很有用。

  • 按值传递的函数,可以使用多种类型的实参,以上述的cube为例:
double z;
z = cube(x+2.1);//1
z = cube(3.14);//2
int y = 10;
z = cube(y);//3

以上的调用都是合法的

  • 但对于refcube(double &ra)来说,如果ra是一个变量的别名,则实参也应该是变量。下面的代码就不合理——表达式x+3.0并不是变量
double num = refcube(x+3.0);
将引用用于结构和类

实际上,引入引用主要是为了用于这些类型,使用结构(类)引用参数的方式与使用基本变量引用相同。假设有如下结构定义:

struct student
{
	char name[20];
	short age;
	int roomnum;
};

则可以这样编写函数原型,在函数中将指向该结构的引用作为参数

void change_room(student & stu);

实例一下:

void change_room(student & stu)
{
	stu.roomnum = 0;
}

student stu1 = {"小明"16,3209}//初始化一个学生结构变量
change_room(stu1);//调用函数

由于change_room(stu1)的形参stu为引用,因此stu指向了stu1,函数体设置了成员stu1.roomnum,就这里而言按值传递不可行,因为这将导致设置的是stu1的临时拷贝的成员roomnum。

如果不希望函数修改传入的结构,可使用const关键字

void show(const student & stu)
{
	std::cout << stu.name << stu.age << stu.roomnum << std::endl;
}

由于show()显示的是结构的内容而不修改它,就这个函数而言,也可按值传递,但与复制原始结构的拷贝相比,使用引用可节省时间和内存。

将引用用于返回值
  • 为何要返回引用?
    传统返回机制与按值传递函数参数类似:计算关键字return后面的表达式,并将结果返回给调用函数。从概念上来说,这个值被复制到一个临时位置,而调用程序将使用这个值。
    如果函数返回一个结构,而不是指向结构的引用,将会先把整个结构复制到一个临时位置,再将这个结构拷贝复制给调用的程序。但在返回值为引用时,将直接把源结构复制到目标结构。
  • 返回引用时需要注意的问题:
    返回引用时最重要的一点:避免返回函数终止时不再存在的内存单元引用,即返回局部变量(或指向局部变量的指针)的引用。
    解决方法有:1.返回一个作为参数传递给函数的引用。
          2.用new来分配新的存储空间。

交换函数比较

#include <iostream>

class swaptest
{
public:
	int x;
	int y;
	swaptest(int a,int b):x(a),y(b) { }//构造函数初始化类成员x,y
	void swapv(int a,int b)
	{
		int temp = a;
		a = b;
		b = temp;
	}
	void swapp(int* a,int* b)
	{
		int temp = *a;
		*a = *b;
		*b = temp;
	}
	void swapr(int &a,int &b)
	{
		int temp = a;
		a = b;
		b = temp;
	}
	~swaptest(){ }
};

int main(int argc, char const *argv[])
{
	using std::cout;
	using std::endl;

	swaptest test(3,10);
	cout << test.x << " "<< test.y << endl;

	test.swapv(test.x,test.y);
	cout << test.x << " " << test.y << endl;
	
	test.swapp(&test.x,&test.y);
	cout << test.x << " " << test.y << endl;
	
	test.swapr(test.x,test.y);
	cout << test.x << " " << test.y << endl;
	return 0;
}

执行结果

各函数执行后结果变量x变量y
初始310
swapv()值传递310
swapp()指针103
swapr()引用310

可以看到,只有值传递的函数没有交换变量的值。引用和指针都成功交换了变量的内容。

  • 先看值传递。swapv函数的操作是将x,y进行对调。需要注意的是,对形参的操作不会影响到a,b。当test.x,test.y把值赋给a,b之后,对a,b不论再做什么操作,都不会影响到test.x,test.y本身。
swapp(int *a, int *b)//函数声明

swapp(&test.x, &test.y)//函数调用
  • 再看地址传递,如上。注意,这时的函数的声明和调用的写法与值传递不同。
    但是与值传递的分析一样,我们可以设想,在swapp函数里,a=&test.x; b=&test.y;表示test.x的地址代入到了a,test.y的地址代入到了b。这样一来,对a, b的操作就是test.x,test.y本身的操作。所以test.x,test.y的值被对调了
swapr(int &a, int &b)// 函数声明

swapr(test.x, test.y)//函数调用
  • 引用传递的函数声明和调用,如上。前面说过,在定义引用变量时必须对其进行初始化。实际上,swapr()函数调用时使用实参test.x,test.y初始化了形参a,b,因此函数的引用参数被初始化为函数调用传递的实参。所以,对引用参数a,b的操作实际上就是对test.x,test.y的直接操作。
    返回
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值