posts - 257, comments - 1327, trackbacks - 52, articles - 8
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

Summary of function parameter

Posted on 2004-07-14 02:33 FantasySoft 阅读(2557) 评论(5)  编辑 收藏 所属分类: All About SoftPure C++Lovely DotNetPractical Java
        对C++这位入得厨房,出得厅堂的MM说爱你说了好几年,却从来没有为她真正献出我的真心;当我看到C#那青春而诱人的身段的时候,我毫不犹豫的拜倒在她裙角下,而狂热的关系仅通过ASP.NET 维系了几个月;花心的我随后跟如斯佳丽般简约唯美的Java度过了半年多疯狂开发的光阴。
        身心疲惫的我重新回到了C++的怀抱,我发现她竟然是那样的Attractive,那样的风华绝代。我会好好爱她的,当然我是不会忘记我的两位情人的。嘿嘿~~~
       
        请大家原谅我说这样的文绉绉的话,我实在太爱她们了。 好,该言归正传了。

        以下是对C++,Java和C#中函数参数的几点总结:
        1. Java函数参数的传递都是传值的;
        2. 而在C#当中,默认的情况下是传值的,而使用了out或者是ref关键字则可以传递引用;
        3. 在C++ 中,可以传值,可以传引用,还可以传递指针。

        从三种语言出现的先后顺序以及她们各自对于函数参数传递的设计,我们或多或少可以体味出一些演变的味道。
        C++诞生得最早,自然也最为灵活,给予了程序员最大的思考空间,然而也正是这样的灵活令C++成为了一把双刃剑,杀退敌人的同时,也可能伤了自己;等到Java横空出世的时候,把指针搁在了一边,连参数传递的方式都只剩下了Pass By Value。这样的设计确实使得编写程序更为简单而程序本身更为健壮,但是一些问题就不太好处理了,下面就会看到一个例子;接着就是我的偶像Anders创造了C#,在我看来,出自世界上最好的程序员之手的C#确实在灵活和简单之间找到了最佳平衡点。在C#中,再次出现了大家熟悉的Pass By Reference,只是&变成了ref。
        C++ :
#include <iostream>

using namespace std;

void swap(int& a, int&
 b)
{
    
int t =
 a;
    a 
=
 b;
    b 
=
 t; 
}


void swapByPointer(int* a, int* b)
{
    
int t = *
a;
    
*= *
b ;
    
*=
 t;
}

void main()
{
    
int a = 5
;
    
int b = 7
;
    cout 
<< a << " " << b <<
 endl;
    swap(a,b);
    cout 
<< a << " " << b <<
 endl;
    swapByPointer(
&a, &
b);
    cout 
<< a << " " << b <<
 endl;
}
         C# :   
using System;

class MainApp
{
      
public static void Main()
{
          
int i = 5
;
          
int j = 7
;
          Console.WriteLine(
"i=" + i + "j=" +
 j);
          swap(
ref i, ref
 j);
          Console.WriteLine(
"i=" + i + "j=" +
 j);
      }

      
public static void swap(ref int i, ref int j){
            
int t =
 i;
            i 
=
 j;    
            j 
=
 t;       
      }

}

        大家会发现C#和C++之间在Pass By Reference上是十分相似的,只是在C#中必须显式的说明传递的是引用还是值。
        在Java中想实现如上的交换两个整数的函数,则由于Java参数传递方式的限制,不得不使用变通的方法了,即使用所谓的
Holder类。因为只有通过对象才能实现隐式的引用传递
        Java :

public class SwapInteger {
    
public static void main(String[] args)
    
{
        IntegerHolder holder1 
= new IntegerHolder();
        IntegerHolder holder2 
= new IntegerHolder();
        holder1.i 
= 5;
        holder2.i 
= 7;
        System.
out.println("Holder1 = " + holder1.i);
        System.
out.println("Holder2 = " + holder2.i);
        swap(holder1, holder2);
        System.
out.println("Holder1 = " + holder1.i);
        System.
out.println("Holder2 = " + holder2.i);
    }

    
public static void swap(IntegerHolder holder1, IntegerHolder holder2)
    
{
        
int i = holder1.i;
        holder1.i 
= holder2.i;
        holder2.i 
= i;
    }

    
static class IntegerHolder
    
{
         
public int i;
    }

}

        对于隐式引用传递,我想再罗嗦几句。因为在Java中,所有的对象都是通过引用来处理的。
        譬如,    
                IntergerHolder holder1 = new IntegerHolder();
        通过new关键字创建了一个类IntegerHolder的实例,而Holder1并不是这个实例的本身,它是这个对象实例的引用(Reference);当一个对象引用作为参数传递的时候,传递的是引用本身的一个copy(即是传值),但是对于对象实例而言,确实传递了引用,因此对象属性的控制权就交到了被调函数手上了,你自然就可以在函数体内任意修改对象的属性了。
        罗嗦老半天了,还请耐心看完这篇Blog的高手们多多指教。

Feedback

#1楼    回复  引用    

2004-07-29 00:50 by virushuo [未注册用户]
我觉得应该这样说比较合适:

java所有基本类型,都是传值,所有类对象,都是传址,如果需要把对象传值,则需要使用.clone()

其实这个很好理解....要记住,vm虚拟的只是一个cpu...所以无论如何,他的行为还是和真正的cpu非常类似的。

#2楼    回复  引用  查看    

2004-08-01 19:03 by 温少      
@virushuo
错,Java只支持按值传递参数。引用类型的传递,是指针地址的值拷贝。

#3楼    回复  引用    

2005-09-27 15:28 by Steven Liu [未注册用户]
在C++中只有两种参数传递方法,传值和传引用,传指针也就是传值。

#4楼 [楼主]   回复  引用  查看    

2005-09-27 17:51 by FantasySoft      
又是一年前的Post,有点FT~~~

To Steven: 如果你把是否能够改变实参作为参数传递方法的划分标准,那么就真的如你所说的,一个是传值,而另一个是传引用。但是指针应该归为哪一类呢?由于指针作为参数传入方法体后是无法指针本身的,这与传值的定义是相符合的。 然而引用又与指针的本质是一样的,只不过不需要显示的disrefence而已,传递指针通常也是为了改变指针所指向的内容,其作用与传引用又是一致的。看到这里,你会觉得把指针传递归为传值是否合适呢?

所以,我会把指针独立处理作为一种参数传递的方式,因为把它归为哪一类都不太合适。

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2005-07-22 14:14 编辑过