2011-05-07 67 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