概要:
教C语言课的过程中,发现很多学生对函数调用中的参数传递问题很容易糊涂。跟师弟交流的过程中,也发现大家对这个问题理解不够透彻。因此,结合本人自己的理解,将函数调用中的传值与传引用进行分析总结。
一、函数调用中传递参数的类型
传值(pass by value):即形参接收实参传递过来的值,如果是自定义类型,要调用拷贝构造函数。函数处理的是形参的值。
传引用(pass by reference):引用表示与原对象完全相同,是同一个对象。若函数的形参是引用,则实参与形参间不存在参数传递,且函数内对形参的修改就是修改实参,因为它们是引用关系,是同一个对象。
1、C语言中,传递的参数类型只有1个:传值,包括传递普通数值和指针。
2、C++中,传递的参数类型有2个:传值、传引用
3、java中,传递的类型只有1个:传值。
java中传的值包括:基本数据类型和对象,其中对象当做指针看待
三种语言的处理方法相同:不管传递的是普通变量还是指针,都是传值。对于指针,看函数修改的是指针的值,还是指针所指对象的值就可以了。
二、程序示例
1、C++:传递的是基本数据类型,包括普通数值、指针和引用
基本数据类型的传参测试
#include
using namespacestd;void swap(int a,intb);void swapPoint(int *pa, int *pb);void swapData(int *pa,int *pb);void swapReference(int &a, int &b);intmain()
{int a = 10;int b = 20;
cout<
swap(a,b);
swapPoint(&a,&b);
swapData(&a,&b);
swapReference(a,b);
cout<
}void swap(int a,intb)
{inttmp;
tmp=a;
a=b;
b=tmp;
cout<
}void swapPoint(int *pa, int *pb)
{int *tmp;
tmp=pa;
pa=pb;
pb=tmp;
cout<
}void swapData(int *pa,int *pb)
{inttmp;
tmp= *pa;*pa = *pb;*pb =tmp;
cout<
}void swapReference(int &a, int &b)
{inttmp;
tmp=a;
a=b;
b=tmp;
cout<
}
分析:
void swap(int a,int b)函数,形参a、b分别接受实参传递的值,函数处理的是形参a、b,实现交换形参a、b的值
void swapPoint(int *pa, int *pb)函数,交换的是指针的值,即交换的是形参的指向关系
void swapData(int *pa,int *pb)函数,交换的是指针所指向的对象,即交换的是实参
2、C++:传递的是自定义类型:结构体或者类
类的传参测试
classTest
{public:inta;
Test()
{
cout<
}
Test(intdata)
{
a=data;
cout<
}
Test(const Test &tmp)
{
a=tmp.a;
cout<
}
};voidswapClass(Test a, Test b)
{
Test tmp;
tmp=a;
a=b;
b=tmp;
}void swapClassReference(Test &a, Test &b)
{
Test tmp;
tmp=a;
a=b;
b=tmp;
}void swapClassPoint(Test *pa, Test *pb)
{
Test tmp;
tmp= *pa;*pa= *pb;*pb =tmp;
}intmain()
{
Test a(10);
Test b= 20;
swapClass(a,b);//swapClassReference(a,b);
swapClassPoint(&a,&b);
cout<
}
分析:swapClassReference(Test &a, Test &b)函数,由于是引用,不会出现拷贝构造函数的调用。形参就是实参
swapClass(Test a, Test b)函数,会调用拷贝构造函数,给a,b分配存储空间。函数处理的是新定义的形参变量a、b
3、java中的参数传递:传值
java中出现对象时,把当做指针看待。例如定义了一个类Test,接下来有定义Test tmp ; //类似于c++的指针,没有调用构造函数
若Test testc = new Test(); //调用默认构造函数
java中传参测试
public classTest
{public intdata;publicString name;publicTest()
{
System.out.println("调用了无参的构造方法Test() ");
}public Test(intdata,String name)
{this.data =data;this.name =name;
System.out.println("调用了有参的构造方法Test(int data,String name) ");
}publicTest(Test src)
{
data=src.data;
name=src.name;
System.out.println("调用了拷贝的构造方法Test(Test src) ");
}publicString toString()
{return "data= "+data+", name= "+name;
}public static voidswap(Test a, Test b)
{
Test tmp ;//类似于c++的指针,没有调用构造函数
tmp =a;
a=b;
b=tmp;
}public static voidmodify(Test a)
{
a.data+= 100;
a.name+=" is modified!";
}public static voidmain(String[] args)
{
Test testA= new Test(2,"testA");
Test testB= new Test(5,"testB");
Test.swap(testA, testB);
Test.modify(testA);
System.out.println("testA: "+testA.toString());
System.out.println("testB: "+testB.toString());
}
}
分析:
主函数中的swap(Test a, Test b)方法,可以证明java中传递的值,而不是引用
modify(Test a)方法中,之所以可以修改属性的值,是因为修改的是指针所指的对象。
总之,java中出现对象时,把当做指针看待
三、总结
1、 C++中传值(特别是对于自定义类型),会带来拷贝构造函数执行的开销,所以执行效率低一点。
传引用和传指针,不执行拷贝构造函数,效率会高
2、当用按值传递方式传递或返回一个对象时,编译器会自动调用拷贝构造函数!
3、当指针作为形参时,最好画出指针所指向的对象。然后分析修改的是指针的值,还是指针所指的对象。
(完)