C++参数传递:传值和传引用
C++不允许函数return数组或多个对象,但很多时候,确实需要一个函数传回多个值。这时就希望函数直接对外部的变量或指针做操作,绕过return来达到目的。引用的概念曾经一直是盲区,觉得&仅可能是取地址符,&a
就是取a
的地址的意思。由此导致很多错误。
引用
在《C++ Primer》(中文第五版,45~46页)中讲到,引用其实是给变量取了一个别名:
int a = 1;
int &ra = a; // ra是a的另一个名字
这时可以讲,ra
和a
指的完全是一个东西,任何对ra
的操作都是对a
的操作。在初始化的过程中,a的值并没有被复制。引用在定义的时候就必须被初始化,并且之后不能重新赋值。
就像*
号在定义和声明过程中代表变量是一个指针,但在赋值等过程中代表解引用符来访问指针所指的对象一样,&
符号在定义引用时,并不是取地址的意思。
函数传值
传值参数
当初始化一个非引用类型的变量时,初始值被拷贝给变量。此时,对变量的改动不会影响初始值。
也就是说,当一个函数被调用时,
void func(int p){p++;}
int main()
{
int a = 1;
func(a);
return 0;
}
实际上是用a
的值对形式参数p
初始化,(相当于隐含了一句int p = a;
),a
这个对象被复制了一份。这时,p
和a
是独立的两个变量,相互不影响。
要同时对多个变量做改变,并且在内部变量生命周期结束后,他们的变化还能影响到外部变量,这时可以声明指针变量做形式参数,
// 交换两个变量的值
#include <iostream>
using namespace std;
int main()
{
int a = 1;
int b = 2;
int *p = &a;
int *q = &b;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
exchange(&a, &b); // 传入对象的地址而不是对象,以此初始化形式参数
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
int exchange(int *p,int *q)
{
int tmp = *p;
*p = *q; // 对指针所指的对象做改变,但不改变指针所指向的地址
*q = tmp;
return 0;
}
在函数内部利用解引用符,直接对存在于相应地址上的对象做改变。这样,当函数执行完毕,p
、q
两个指针变量被销毁,a
、b
的值被交换。
这也是指针的好处之一吧,可以实现很灵活的操作。
传引用参数
类似地,如果函数的形式参数是一个引用,在调用这个函数时,仍然使用初始值对形式参数进行初始化,相当于隐含了一个引用的初始化过程int &p = a;
:
int exchange2(int &a,int &b) // 调用时要传入对象而不是对象的地址
{
int tmp = a;
a = b;
b = tmp;
return 0;
}
这样,并没有对象被复制,而是给外部变量a
起了一个别名。可以理解为,在函数内部,p
就是a
,对p
的改变就是对a
的改变。
与值传递相比,引用传递的优势主要体现在三个方面:一是可以直接操作引用形参所引的对象;二是使用引用形参可以避免拷贝大的类类型对象或容器类型对象;三是使用引用形参可以帮助我们从参数中返回多个值
有的时候,函数只读取某个外部对象,并不希望对它做改变,这时,使用常量引用const int &p
,这样可以防止对对象做改变。