wly603

C、C++、java中函数的参数:传值 or 传引用

概要:

     教C语言课的过程中,发现很多学生对函数调用中的参数传递问题很容易糊涂。跟师弟交流的过程中,也发现大家对这个问题理解不够透彻。因此,结合本人自己的理解,将函数调用中的传值与传引用进行分析总结。

 

一、函数调用中传递参数的类型

      传值(pass by value):即形参接收实参传递过来的值,如果是自定义类型,要调用拷贝构造函数。函数处理的是形参的值。

      传引用(pass by reference):引用表示与原对象完全相同,是同一个对象。若函数的形参是引用,则实参与形参间不存在参数传递,且函数内对形参的修改就是修改实参,因为它们是引用关系,是同一个对象。

 

   1、C语言中,传递的参数类型只有1个:传值,包括传递普通数值和指针。

   2、C++中,传递的参数类型有2个:传值、传引用

   3、java中,传递的类型只有1个:传值。

         java中传的值包括:基本数据类型和对象,其中对象当做指针看待

  三种语言的处理方法相同: 不管传递的是普通变量还是指针,都是传值。对于指针,看函数修改的是指针的值,还是指针所指对象的值就可以了。

 

二、程序示例

1、C++:传递的是基本数据类型,包括普通数值、指针和引用

基本数据类型的传参测试
#include <iostream>
using namespace std;

void swap(int a,int b);
void swapPoint(int *pa, int *pb);
void swapData(int *pa,int *pb);
void swapReference(int &a, int &b);

int main()
{
    int a = 10;
    int b = 20;

    cout<<"main函数中, a=  "<<a<<"  b= "<<b<<endl;

    swap(a,b);
    swapPoint(&a,&b);
    swapData(&a,&b);
    swapReference(a,b);

    cout<<"main函数中, a=  "<<a<<"  b= "<<b<<endl;
    return 1;
}

void swap(int a,int b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;

    cout<<"swap函数中, a=  "<<a<<"  b= "<<b<<endl;
}

void swapPoint(int *pa, int *pb)
{
    int *tmp;
    tmp = pa;
    pa = pb;
    pb = tmp;
    
    cout<<"swapPoint函数中, a=  "<<*pa<<"  b= "<<*pb<<endl;
}

void swapData(int *pa,int *pb)
{
    int tmp;
    tmp = *pa;
    *pa = *pb;
    *pb = tmp;
    
    cout<<"swapData函数中, a=  "<<*pa<<"  b= "<<*pb<<endl;
}

void swapReference(int &a, int &b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
    
    cout<<"swapReference函数中, a=  "<<a<<"  b= "<<b<<endl;
}

分析:

       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++:传递的是自定义类型:结构体或者类

类的传参测试
class Test
{
public:
    int a;

    Test()
    {
        cout<<"Test() 无参构造函数!"<<endl;
    }

    Test(int data)
    {
        a = data;
        cout<<"Test(int data) 有参构造函数!"<<endl;
    }

    Test(const Test &tmp)
    {
        a = tmp.a;
        cout<<"拷贝构造函数!!"<<endl;        
    }
};

void swapClass(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;
}

int main()
{
    Test a(10);
    Test b = 20;

    swapClass(a,b);
//    swapClassReference(a,b);
    swapClassPoint(&a,&b);

    cout<<a.a<<"    "<<b.a<<endl;

    return 1;
}

分析: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 class Test 
{
    public int data;
    public String name;
    
    public Test()
    {
        System.out.println("调用了无参的构造方法Test() ");
    }
    public Test(int data,String name)
    {
        this.data = data;
        this.name = name;
        System.out.println("调用了有参的构造方法Test(int data,String name) ");
    }
    
    public Test(Test src)
    {
        data = src.data;
        name = src.name;
        System.out.println("调用了拷贝的构造方法Test(Test src) ");
    }
    
    public String toString()
    {
        return "data= "+data+", name= "+name;
    }
    public static void swap(Test a, Test b)
    {
        Test tmp ; //类似于c++的指针,没有调用构造函数
        tmp = a;
        a = b;
        b = tmp;
    }
    
    public static void modify(Test a)
    {
        a.data += 100;
        a.name +=" is modified!";
    }
    public static void main(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、 当指针作为形参时,最好画出指针所指向的对象。然后分析修改的是指针的值,还是指针所指的对象。

 

(完)

posted on 2012-05-23 15:32  wly603  阅读(3438)  评论(5编辑  收藏  举报

导航