2011-05-07 74 views
2

据说在Java中,方法参数是通过值传递的,对于基元和对象来说是真实的,对象的引用是通过值传递的。为了说明考虑的代码:Java和C++按值传递并通过引用

class Test { 
private static void dateReplace (Date arg) { 
     arg = new Date (arg.getYear(), arg.getMonth(), arg.getDate() +1); 
     System.out.println ("arg in dateReplace: " + arg); 
    } 

public static void main(String[] args) { 

     Date d1 = new Date ("1 Apr 2010"); 
     dateReplace(d1); 
     System.out.println ("d1 after calling dateReplace: " + d1); 
    } 
} 

this will print: 
arg in dateReplace: Fri Apr 02 00:00:00 2010 
d1 after calling dateReplace: Thu Apr 01 00:00:00 2010. 

什么是C++等效,会给出相同的结果?

什么是C++等价物,它会在调用方法后给出d1的值与方法内的值相同,即调用者可以看到修改后的值?

+0

这功课吗?您可能想要阅读C的*(间接)和&(引用)操作符。 – eggyal 2011-05-07 15:44:18

+3

@eggyal C和C++都没有引用操作符 - &是操作符的地址。 – 2011-05-07 15:51:03

+0

@unapersson:有什么区别? :s – eggyal 2011-05-07 16:00:13

回答

5

对于值和引用,C++不具有与Java相同的语义。起初,每种类型都有可能通过复制或通过引用或通过地址传递(然而,您可以通过隐藏复制构造函数来防止类型通过复制传递)。

与Java的“通过引用”传递关系最密切的传递类型是通过指针。这里是三个的示例:

void foo(std::string bar); // by copy 
void foo(std::string& bar); // by reference 
void foo(std::string* bar); // by address 

作为边注,路过副本总是大于通过引用或指针传递用于比指针的大小较大的类型更昂贵。出于这个原因,您也可能更喜欢传递const引用,这将允许您读取对象而不必复制它。

void foo(const std::string& bar); // by const reference 

但是,这是非常棘手的,你需要知道Java的细微之处,以正确地决定你想要在C++中。在Java中,你实际上并不是通过引用来传递对象:你通过复制来传递对象引用。也就是说,如果将新对象分配给参数,则父范围的对象不会更改。在C++中,这通过地址比通过引用更加紧密地匹配传递对象。这里有一个如何这是很重要的一个例子:

// Java using "object references": 
public static void foo(String bar) 
{ 
    bar = "hello world"; 
} 

public static void main(String[] argv) 
{ 
    String bar = "goodbye world"; 
    foo(bar); 
    System.out.println(bar); // prints "goodbye world" 
} 

// C++ using "references": 
void foo(std::string& bar) 
{ 
    bar = "hello world"; 
} 

int main() 
{ 
    std::string bar = "goodbye world"; 
    foo(bar); 
    std::cout << bar << std::endl; // prints "hello world" 
} 

// C++ using pointers: 
void foo(std::string* bar) 
{ 
    bar = new std::string("goodbye world"); 
    delete bar; // you don't want to leak 
} 

int main() 
{ 
    std::string bar = "goodbye world"; 
    foo(&bar); 
    std::cout << bar << std::endl; // prints "hello world" 
} 

换句话说,当你在C++中使用引用,你真的与你们打交道通过相同的变量。您对它做的任何更改,甚至是分配,都会反映到父范围中。 (这部分是由于C++如何处理赋值操作符)。使用指针,您会得到一个与您使用Java引用的行为关系更密切的行为,代价是可能必须通过一元运算符&获取对象地址(参见我的示例中的foo(&bar)),需要使用->运算符来访问成员,以及使用运算符重载的一些额外复杂性。

另一个值得注意的区别是,由于使用by-reference参数与by-copy参数的使用在语法上密切相关,所以函数应该能够假设您通过引用传递的对象是有效的。尽管通常可以将引用传递给NULL,但是非常不鼓励,因为实现它的唯一方法是取消引用NULL,该引用具有未定义的行为。因此,如果您需要能够通过NULL作为参数,则您更愿意按地址而不是按引用传递参数。

大多数情况下,当您想从函数修改参数时,您希望通过引用而不是地址传递,因为它更“C++友好”(除非需要NULL值),即使它不完全像Java所做的那样。

+1

Java可能会将它们称为对象引用。但它们更像是C++指针而不是引用,因为它们可以是NULL。所以我只是将Java对象看作垃圾收集指针,它基本上相当于一个C++共享指针(这只是一个更精细的谷物垃圾收集指针)。 – 2011-05-07 18:00:57

0
class Test { 
void dateReplaceReference(Date& arg) { 
    // arg is passed by reference, modifying arg 
    // will modify it for the caller 
} 
void dateReplaceCopiedArgument(Date arg) { 
    // arg is passed by value, modifying arg 
    // will not modify data for the caller 
} 
void dateReplaceByPointer(Date* arg) { 
    // arg is passed as pointer, modifying *arg 
    // will modify it for the caller 
} 
}; 

请注意,作为参考或指针传递是相同的事情。唯一的区别是你想要访问数据的方式是“。”或按“ - >”。另外,你不能将一个空值传递给一个引用的方法。

+0

实际上,修改'* arg'会修改调用者的数据。修改'arg'不会。 – nos 2011-05-07 16:00:43

+0

是的,这是错的。通过指针访问某些内容会改变所有用户的对象。唯一能让更改不可见的方法是第二种方法,其中为arg调用复制构造函数,并仅调用给被调用者的副本。 – Voo 2011-05-07 16:37:53

+0

你是对的! :) – ralphtheninja 2011-05-07 16:49:45

1

默认情况下,C++按值传递。您可以通过编写接受引用的函数或通过传递指针来显式传递引用。

考虑以下三个例子:

FooByValue(Foo arg) 
{ 
    //arg is passed by value. 
} 

FooByReference(Foo & arg) 
{ 
    //arg is passed by reference. 
    //changes made to arg will be seen by the caller. 
} 

FooByPointer(Foo * arg) 
{ 
    //arg is passed by reference with pointer semantics. 
    //changes made to the derefenced pointer (*arg) will be seen by the caller. 
} 

然后,您可以拨打以上如下 富anObject;

FooByValue(anObject); //anObject will not be modified. 
FooByRefence(anOBject); //anOBject may be modified. 
FooByPointer(&anObject); //anObject may be modified. 

当应用于像&anOBject一个变量&符号用于获取变量的地址,基本上给人一种指针位置内存变量存储英寸

FooByValue()运作就像你例如,FooByReference()将在函数调用后保留对参数所做的任何更改,因为参数不会被复制,它在内存中的实际位置将被共享。

+0

错了。在C++中没有任何引用通过。这是一个普遍的误解。您按值传递引用/指针。如果它是通过引用传递的,则可以修改参数本身(而不仅仅是它指向的对象/引用)。 – 2011-05-07 15:51:55

+5

@Tamas你似乎对“传引用”这个术语有着你自己的私有含义。 – 2011-05-07 15:55:42

+0

如果通过指针传递对象,是否可以修改函数内的指针,使其指向其他位置,并且更改会反映到外部?例如,你可以在Pascal中做到这一点,因为它实际上具有[通过引用语义](http://www.hkbu.edu.hk/~bba_ism/ISM2110/pas045.htm)。你不能在C++中做到这一点。 – 2011-05-07 15:58:15