【C++】引用

一、引用的概念

参数的传递本质上是一次赋值的过程,赋值就是对内存进行拷贝。所谓内存拷贝,是指将一块内存上的数据复制到另一块内存上。

对于像 char、bool、int、float 等基本类型的数据,它们占用的内存往往只有几个字节,对它们进行内存拷贝非常快速。而数组、结构体、对象是一系列数据的集合,数据的数量没有限制,可能很少,也可能成千上万,对它们进行频繁的内存拷贝可能会消耗很多时间,拖慢程序的执行效率。

C/C++禁止在函数调用时直接传递数组的内容,而是强制传递数组指针。而对于结构体和对象没有这种限制,调用函数时既可以传递指针,也可以直接传递内容;为了提高效率,可以传递指针。

但是在 C++ 中,我们有了一种比指针更加便捷的传递聚合类型数据的方式,那就是引用(Reference),用&表示

引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据

引用的语法格式如下:

Type &name=data
/*
Type 是被引用的数据的类型;
name是引用的名称;
data是被引用的数据
*/

使用引用的规则:

1)引用被创建时,必须被初始化(指针可以在任何时候被初始化)。

2)一旦一个引用被初始化为指向一个对象,就不能改变为另一个对象的引用(指针可以在任何时候指向另一个对象)。

3)没有NULL引用。必须确保引用是一块合法的存储单元关联。

示例演示:

    int a = 10;
	int& num = a;   //&表示引用
	cout << "a的地址:"<< &a << endl;  //&表示取地址
	cout << "a的值:" << a << endl;
	cout << "num的地址:" << &num << endl;
	cout << "num的值:" << num << endl;

	num = 100;
	cout << "a的地址:" << &a << endl;
	cout << "a的值:" << a << endl;
	cout << "num的地址:" << &num << endl;
	cout << "num的值:" << num << endl;

 由上结果可知,变量a和引用num表示的是同一份数据,同一块内存,所以无论通过变量a还是num都是访问同一数据。通过对引用修改也可以修改原始变量所存储的数据。

常引用

如果不希望通过引用来修改原始数据,那么可以在定义时添加const 进行限制,语法格式如下:

const Type &num=data;
或
Type const &num=data;

这种引用方式称为常引用。 

示例演示:

	int a = 10;
	const int& num = a;
	num = 100;//编译时报错,提示不能给常量赋值

二、函数中的引用

引用作为函数参数

在函数定义或声明时,可以将函数的形参指定为引用的形式,这样调用函数时就会将实参和形参捆绑在一起,让它们指代同一份数据。这样,函数体中对形参进行修改,那么实参也会被修改

示例演示:

void swap1(int a, int b);
void swap2(int* p1, int* p2);
void swap3(int& r1, int& r2);

//直接传递参数内容
void swap1(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
}

//传递指针
void swap2(int* p1, int* p2) {
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

//按引用传参
void swap3(int& r1, int& r2) {
	int temp = r1;
	r1 = r2;
	r2 = temp;
}

int main() {
	int num1=10, num2=20;
	swap1(num1, num2);
	cout << num1 << " " << num2 << endl;

	swap2(&num1, &num2);
	cout << num1 << " " << num2 << endl;
	
	swap3(num1, num2);
	cout << num1 << " " << num2 << endl;
	return 0;
}

 由以上结果可知,通过值传递的方式,不能达到交换两个数的目的。传指针或传引用都能达到交换目的。

参数传递原则:

传值方式需要调用构造函数和析构函数,如果不想改变参数,则可通过常量引用传递,它仅需要将地址压栈。只有一种情况不适合用传递地址,就是传值为唯一安全的途径。

 引用作为函数返回值

int& Myplus(int& i)
{
	i += 1;
	return i;
}

int main()
{
	int num = 10;
	int num2 = Myplus(num);
	cout << num << endl;
	cout << num2 << endl;
	cout << &num << endl;
	cout << &num2 << endl;
}

将引用作为函数返回值时应注意不能返回局部数据(例如局部变量、局部对象、局部数组)的引用,因为当函数调用完成后局部数据就会被销毁,可能下次使用时数据就不存在了。

int& Myplus(int& i)
{
	int temp = i;
	temp += 1;
	return temp;
}

int main()
{
	int num = 10;
	int num2 = Myplus(num);
	cout << num << endl;
	cout << num2 << endl;
	int &num3 = Myplus(num);
	int &num4 = Myplus(num3);
	cout << num << endl;
	cout << num3 << endl;
	cout << num4 << endl;
	
}

 上面结果并非我们想要的结果。导致结果怪异的原因就是返回一个局部变量的引用。第二次调用Myplus时会覆盖第一次调用Myplus产生的局部变量,第三次同理。

三、临时对象

C++的临时对象是不可见的匿名对象,但程序在运行时确实生成了的对象。

以下是产生临时对象的场景:

1)构造函数作为隐式类型转换函数时,会创建临时对象,用作实参传递给函数

class Integer
{
public:
	Integer(int i) :m_val(i) 
	{
		cout << "constructor" << endl;
	}
	~Integer() 
	{
		cout << "destructor" << endl;
	}
	int getVal()
	{
		return m_val;
	}
private:
	int m_val;
};

void testFunc(Integer itgr)
{
	cout << itgr.getVal() << endl;
}

int main()
{
	int i = 10;
	testFunc(i);//产生临时变量
}

 

testFunc(i)会调用构造函数Integer(int i)进行隐式数据转换产生一个临时对象,作为实参传递到testFunc函数中。

消除临时对象方法:只能尽量避免隐式转换

2)函数返回一个对象时,会产生临时对象。以返回的对象最作为拷贝构造函数的实参构造一个临时对象。

class Integer
{
public:
	Integer()
	{
		cout << "default-Constructor" << endl;
	};

	Integer(const Integer& arg)
	{
		this->m_val = arg.m_val;
		cout << "Copy Constructor" << endl;
	};

	Integer(int i) :m_val(i) {
		cout << "Constructor" << endl;
	};

	Integer& operator=(const Integer& arg)
	{
		cout << "Assignment operator function" << endl;
		if (this != &arg)  //防止自赋值
		{
			this->m_val = arg.m_val;
		}
		return *this;
	}

	~Integer() {};

	int m_val;
};

Integer testFunc(Integer inter)
{
	inter.m_val++;
	cout << "before return" << endl;
	return inter;
}
int main(int argc, char* argv[])
{
	Integer inter(5);//Constructor
	Integer resutl; //default constructor
	resutl = testFunc(2);//Constructor,then Copy Constructor,then Assignment operator
	cout << resutl.m_val << endl;
	return 0;
}

 消除临时对象方法:以引用的方法返回

void testFunc(Integer& inter)
{
	inter.m_val++;
	cout << "before return" << endl;
	
}

int main(int argc, char* argv[])
{
	Integer inter(5);//Constructor
	Integer resutl; //default constructor
	testFunc(inter);//这样就不会产生临时变量
	cout << inter.m_val << endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值