普通的形参是通过复制对应的实参进行初始化,被调用的函数并没有访问所传递的实参本身,而只是使用了实参的副本。
int gcd(int v1,int v2)
{
。。。。。
}
gcd(i,j); //可以这样理解:在调用函数gcd时,初始化int v1=i,int v2=j;有
了这样的理解,把实参传递给形参时要注意的事项就容易弄明白
了,尤其是形参中有const的时候。
上面这个例子中,v1,v2是i,j的副本,在函数中对v1和v2的操作不会对i和j产生任何影响。若想要操作v1,v2就相当于对i和j进行操作,那就需要将形参定义为指针或者引用。
指针形参
void gcd(int *ip)
{
。。。。。。
}
int main()
{
int i=19;
int *p=&i;
gcd(p); //ok
gcd(&i); //ok
}
在上面的gcd函数中对*ip的操作就是对i的操作,可以在gcd函数中改变i的值。我们在指针形参中加入const限定符,
void gcd(const int *ip)
{
。。。。。
}
这里的区别是不可以通过函数gcd改变*ip的值,这样就保证了实参不会被修改。const int *ip是指向const对象的指针,既可以用const对象对其初始化也可以是非const对象。所以,调用函数gcd,既可以用“int *”也可以用“const int *”类型的实参。
const形参
void gcd(int p){……}
const int i=10;
gcd(i); //ok,因为用const变量可以初始化非const变量
另外,
void gcd(const int p){………}
int i=10;
gcd(i); //ok
这两个小例子不难理解,类比const常量的初始化即可,只是在第二个例子中,形参p是不可修改的。
const引用形参
引用是变量的别名,用引用作为形参,可以避免在调用函数时复制实参,在被调用的函数中对形参的操作就是对实参的操作。当const引用作为了形参,就要注意const引用的特殊情况,
void gcd(const int &p){…….}
int i=10;
double j=20.5;
const int k=30;
gcd(i); //ok
gcd(j); //ok
gcd(k); //ok
类比const引用的初始化,很好理解上面的例子,有一点需要注意的是在函数gcd中p是不可修改的。
在非const引用中,实参不可以是const对象,因为在函数中是可以对形参进行修改的,而实参是不可以修改的类型,
void gcd(int &p){……}
const int i=10;
gcd(i); //error p是i的别名,i是不可以被修改的,而p却是可以被修改的实参