引用做函数参数与引用做函数返回值

部分参考博客:http://t.csdn.cn/b5x99

引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参

优点:可以简化指针修改实参

值传递:就是函数调用实参时,将数值传入给形参,值传递时形参是修饰不了实参的

地址传递:函数调用时,实参将地址传入给形参

//1. 值传递
void mySwap01(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

//2. 地址传递
void mySwap02(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

//3. 引用传递
void mySwap03(int& a, int& b) {//注意这里,传参数时就是对引用的初始化
    int temp = a;
    a = b;
    b = temp;
}

int main() {

    int a = 10;
    int b = 20;

    mySwap01(a, b);
    cout << "a:" << a << " b:" << b << endl;

    mySwap02(&a, &b);
    cout << "a:" << a << " b:" << b << endl;

    mySwap03(a, b);
    cout << "a:" << a << " b:" << b << endl;

    system("pause");
    return 0;
}

 总结:通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单

引用做函数返回值

引用是可以作为函数的返回值存在的,引用作为函数的返回值时,必须在定义函数时在函数名前加上&

下面从四种情况进行对比分析

有fn1和fn2两个函数,temp为全局变量

//代码来源:RUNOOB
#include<iostream>
using namespace std;


float temp;//全局变量

float fn1(float r){
    temp=r*r*3.14;
    return temp;
} 

float &fn2(float r)//&说明返回的是temp的引用,换句话说就是返回temp本身
{ 
    temp=r*r*3.14;
    return temp;
}


int main(){
    float a=fn1(5.0); //case 1:返回值

    //float &b=fn1(5.0); //case 2:用函数的返回值作为引用的初始化值 [Error] invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float'
                           //(有些编译器可以成功编译该语句,但会给出一个warning) 

    float c=fn2(5.0);//case 3:返回引用

    float &d=fn2(5.0);//case 4:用函数返回的引用作为新引用的初始化值

    cout<<a<<endl;//78.5
    //cout<<b<<endl;//78.5
    cout<<c<<endl;//78.5
    cout<<d<<endl;//78.5

    return 0;
}

case 1:用返回值方式调用函数

返回全局变量temp的值时,C++会在内存中创建一个临时的变量,并将temp的值拷贝给该临时变量。当返回到主函数main后,赋值语句a=fn1(5.0)会把临时变量的值再拷贝给变量a

case 2:用函数的返回值初始化引用的方式调用函数

这种情况下,函数fn1()是以值方式返回,返回时,首先拷贝temp的值给临时变量。返回到主函数后,用临时变量再来初始化引用变量b,使得b成为该临时变量的别名。由于临时变量的作用域短暂(在C++标准中,临时变量或对象的生命周期在一个完整的语句表达式结束后便宣告结束,也就是在语句float &b=fn1(5.0);之后) ,而b是临时变量的别名,所以b会面临无效的危险,很有可能以后的值是个无法确定的值。

case 3:用返回引用的方式调用函数

这种情况下,函数fn2()是以引用的方式返回,返回的是temp的本身,他不会产生副本,而是直接将变量temp返回给主函数,即主函数的赋值语句中的左值是直接从变量temp中拷贝而来(也就是说c只是变量temp的一个拷贝而非别名) ,这样就避免了临时变量的产生。尤其当变量temp是一个用户自定义的类的对象时,这样还避免了调用类中的拷贝构造函数在内存中创建临时对象的过程,提高了程序的时间和空间的使用效率

case 4:用函数返回的引用作为新引用的初始化值的方式来调用函数

这种情况下,函数fn2()的返回值不产生副本,而是直接将变量temp返回给主函数。在主函数中,一个引用声明d用该返回值初始化,也就是说此时d成为变量temp的别名。由于temp是全局变量,所以在d的有效期内temp始终保持有效,故这种做法是安全的。

总结:引用作函数的返回值的最大的好处是在内存中不产生返回值的副本。

此外还需要注意,不要返回局部变量引用

//返回局部变量引用
int& test01() {
	int a = 10; //局部变量
	return a;
}

//返回静态变量引用
int& test02() {
	static int a = 20;//全局区
	return a;
}

int main() {

	//不能返回局部变量的引用
	int& ref = test01();
	cout << "ref = " << ref << endl;//ref=10
	cout << "ref = " << ref << endl;//乱码

	//如果函数做左值,那么必须返回引用
	int& ref2 = test02();
	cout << "ref2 = " << ref2 << endl;
	cout << "ref2 = " << ref2 << endl;

	test02() = 1000;

	cout << "ref2 = " << ref2 << endl;
	cout << "ref2 = " << ref2 << endl;

	system("pause");

	return 0;
}

调用test01函数,第一次输出正常,第二次输出乱码

此外,如果函数的返回值是一个引用,这个函数调用可以作为左值。

猜你喜欢

转载自blog.csdn.net/hbzdsXCV/article/details/128355689