C++函数参数传递:按值传递和按引用传递


 
    

#include<iostream>ios

using namespace std;程序员

void swap1(int a,int b);安全

void swap2(int* a,int *b);ide

void swap3(int& a,int& b);函数

int main()spa

{.net

int a=2,b=3;指针

swap1(a,b);对象

cout<<"a="<<a<<endl;blog

cout<<"b="<<b<<endl;

swap2(&a,&b);

cout<<"a="<<a<<endl;

cout<<"b="<<b<<endl;

swap3(a,b);

cout<<"a="<<a<<endl;

cout<<"b="<<b<<endl;

}

void swap1(int a,int b)

{

int temp = a;

a = b;

b = temp;

}

void swap2(int* a,int *b)

{

int* temp =a;

a = b;

b = temp

}

void swap3(int& a,int& b)

{

int temp = a;

a = b;

b =temp;

}


1、按值传递
这种传递方式继承自C语言。上述程序中的swap1和swap2函数使用这种传递方式,可是两种函数的做用并不相同。swap1函数没有达到交换a和b的值的目的,而swap2函数达到了交换a和b的值的目的;即便如此二者仍然同属于“按值传递”。
按值传递的特色是:在函数调用时,系统会在函数做用域新建形参存储空间并用实参对其初始化,因此调用时形参是实参的一个副本。然而为何swap1和swap2效果不一样呢?由于在swap1中a是main中a的副本、b是main中b的副本,更改swap1函数做用域中的a和b中的值并不影响main函数做用域中a和b的值;然而swap2中传递的是main中a和b的地址,通过地址能够更改传递过来的地址指向的值。
2、按引用传递
这种传递方式是C++语言新添加的特性。经过传递对参数的引用,能够容许函数访问(甚至修改)参数变量。要想按引用传递,必须将函数参数声明为引用。
函数swap3达到了交换a和b值的目的,从函数声明中能够看出swap3和swap1惟一的区别是在int后添加了一个字符“&”,正是这个字符使函数swap3中的a和b是main函数中a和b的引用。(“引用”即“别称”,注意:对引用对象的任何操做,做用于原来的对象。)

对比两种传递方式:
按值传递变量,须要有复制实参内存以初始化形参,因此这将带来一些开销。在讨论简单变量时,内置的类型(如int、float)的开销能够忽略不计,但对于大型的对象(如表明整个3D世界的大对象)来讲,复制的代价会很高昂。C语言也提供了一种指针式的“按值传递”,也能够解决传递大对象时代价太高的问题,然而“指针”因为安全问题一直为众多程序员所诟病。故而C++又提供了一个按引用传递。
按引用传递:按值传递没法修改实参的值,由于它形参永远是实参的副本;然而按引用传递能够修改实参的值。

某些状况下,咱们须要修改实参的值,而某些状况下,咱们不想修改实参的值。
在C语言中咱们的解决方案:若是不想修改咱们就直接传递实参,若是对象太大咱们就传递指针,而且声明指针是指向const对象的;若是想修改实参的值,咱们只能传递实参的指针,然而此时指针就不能用const修饰了。
在C++中,咱们仍然能够使用C中的方式,然而也能够使用“引用”方式:若是不想修改实参的值,咱们使用const引用(就是“常量引用”)方式,这样就不能够经过引用修改被引用对象的值;若是想修改实参的值,则使用日常性的引用实参就能够了(如上程序)。

使用const引用作函数参数的举例:void display(const vector<string>& vec);








一直分不清楚他们是干什么的,这回好好的总结下:

1:按值传递:

    程序以下:

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3. void swap(int a,int b)//指针保存地址  
  4. {  
  5. int c;  
  6. cout<<"前: a:"<<a<<"  b:"<<b<<endl;  
  7. c=a;  
  8. a=b;  
  9. b=c;  
  10. cout<<"后: a:"<<a<<"  b:"<<b<<endl;  
  11. }  
  12. int main()  
  13. {  
  14.     int a=3,b=4;  
  15.     cout<<"主程序前: a:"<<a<<"  b:"<<b<<endl;  
  16.     swap(a,b);//取地址传递 变量的内存地址  
  17.     cout<<"主程序后: a:"<<a<<"  b:"<<b<<endl;  
  18.     return 0;  
  19. }  

输出的结果是:

主程序前: a:3  b:4

前: a:3  b:4

后: a:4  b:3

主程序前: a:3  b:4

主程序的值没有改变,改变的值是栈中的a 和b的副本的值,值传递的时候在栈中拷贝一个变量的副原本操做,这样的话就改变不了之前的值.用的时候要当心.

       

2:按址传递:

这个时候是用地址传递 程序以下:

 

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3. void swap(int *a,int *b)//指针保存地址  
  4. {  
  5. int c;  
  6. cout<<"前: a:"<<*a<<"  b:"<<*b<<endl;  
  7. c=*a;  
  8. *a=*b;  
  9. *b=c;  
  10. cout<<"后: a:"<<*a<<"  b:"<<*b<<endl;  
  11. }  
  12. int main()  
  13. {  
  14.     int a=3,b=4;  
  15.     cout<<"主程序前: a:"<<a<<"  b:"<<b<<endl;  
  16.     swap(&a,&b);//取地址传递 变量的内存地址  
  17.     cout<<"主程序后: a:"<<a<<"  b:"<<b<<endl;  
  18.     return 0;  
  19. }  

这个就是按地址传递 在方法swap(&a,&b);的参数中&a ,&b都是取地址 那么传递过去的地址由指针来接收 因此在定义函数的时候有void swap(int *a,int *b)定义了俩个指针来存放地址,这样就好理解了 swap(){}函数里面的操做都是按指针来操做的*a ,*b

这样的话结果就是:

主程序前: a:3  b:4

前: a:3  b:4

后: a:4  b:3

主程序前: a:4  b:3

能够看到结果是改变了,由于直接操做的是a,b的内存地址

 

3:按别名(引用)传递:

 

[c-sharp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3. void swap(int &a,int &b)//接收俩个别名  
  4. {  
  5. int c;  
  6. cout<<"前: a:"<<a<<"  b:"<<b<<endl;  
  7. c=a;  
  8. a=b;  
  9. b=c;  
  10. cout<<"后: a:"<<a<<"  b:"<<b<<endl;  
  11. }  
  12. int main()  
  13. {  
  14.     int a=3,b=4;  
  15.     cout<<"主程序前: a:"<<a<<"  b:"<<b<<endl;  
  16.     swap(a,b);//直接传递a b 传递过去的时候由别名接收 那么就是自身的别名了  
  17.     cout<<"主程序后: a:"<<a<<"  b:"<<b<<endl;  
  18.     return 0;  
  19. }  
  

  这样的话 接受的参数就是俩个别名,他们分别是主函数中a b的别名,由于别名和自身同样 因此结果就改变了

主程序前: a:3  b:4

前: a:3  b:4

后: a:4  b:3

主程序前: a:4  b:3

能够看到用值传递一不当心就达不到目的了,用地址传递的话写法会比较困难,不当心会出错,用引用传递的话考虑的问题就没有那么多了,咱们就能够放心的使用了,写函数的时候用引用,那么调用的时候就不用考虑太多了.