C++的operator overloading和&之問

以下的程式碼除非註明,全部都是出自於

C++ How to program 5d, DEITEL

------------------------------------------------------------------------

首先很奇怪的是這兩行

friend ostream &operator<<( ostream &, const Array & );

friend istream &operator>>( istream &, Array & );

我不懂的是,為甚麼ostream和istream不論傳入或傳回,都一定要是用pass by reference的方式

我有自己竄改過這段碼,把&都拿掉,然後compile之後就跟我說一個ios_base.h(這應該是預設的header吧?)裡面有一段出錯...

所以很明顯的是原本就不允許pass by value,不過為甚麼呢?

我爬了一下知識正裡的文,有人說用&只是方便debug...很顯然的好像不只是debug好de的感覺,根本就不能不用&嘛!

-----------------------------------------------------------------------

第二

HugeInt &HugeInt::operator=(const HugeInt &op2){//=

for(int i = 0;i <= 29;i++)

integer[i] = op2.integer[i];

numsign = op2.numsign;

return *this;

}

這是一段我很久以前自己寫的碼

是在為一個名叫HugeInt的class作=的overloading

應該很容易看得出來

只是奇怪的有三點

第一點,如果我把HugeInt &HugeInt::operator=(const HugeInt &op2)裡,const HugeInt &op2的const給拿掉,就會出問題,程式中任何一個會作assign的第方都會error

為甚麼傳入的部分會規定一定要寫const@@?

第二點,我當初其實忘了寫 return *this;這一行,但是居然都沒有出錯...其實函數就算在不是void的情況下也還是可以不回傳值嗎@@?

不過如果我要做a = b = c這種casecading的把戲的時候就會掛掉...

所以感覺起來,單純的a = b,其實是用copy constructor去做的嗎?

第三點,我又手癢把HugeInt &HugeInt::operator=(const HugeInt &op2)裡中的const HugeInt &op2的&給拿掉了,結果就變成link error?「 [Linker error] undefined reference to `HugeInt::operator=(HugeInt const&)' 」

可是我在definition那裡的&也拿掉了啊@@怎麼會link error...

還有,如果沒有link error的話,pass by value的參數傳入是合法的沒錯吧?

---------------------------------------------------------------------------

第三問:

const Array &operator=( const Array & );

為甚麼他這麼喜歡回傳用&??

幾乎全部這本書中的operator overloading都用&

這樣如果回傳的不是*this的話,不就會被砍掉了嗎囧

是為了效率問題嗎...?

--------------------------------------------------------------------------

我知道問題有點多

不過都是圍繞同一個主題的

希望有強者可以詳細的幫我解說

因為以前的強者好像都不太仔細講這裡

知識正以前好像也沒有人這麼喜歡問這裡

但是這個部分(&,const...)真的是這裡很玄妙的地方

很難決定甚麼時候用pass by value甚麼時候pass by reference

甚麼時候回傳要const,甚麼時候不需要const = =

順便小抱怨一下

知識正的標題可以容納的太短了吧

這樣很難把問題描述清楚

然後知識正對於有相似的問題又不準問

!@#$%^&*...

要嘛就可以讓我把標題打長一點來增加辨識度啊

不然就不要做這麼煩人的擋問設計嘛...

希望我的抱怨有人會聽到...

但是請不要為了這個砍我帳號...我只是給個建議而已

Update:

回答novus大的問題:

pass by reference是用一個reference去指向傳來的變數,也就是說,這個變數本身並沒有被複製一次。

pass by value 是建立一個新的變數去複製一個傳來的變數,所以其實原來的變數並沒有真的被傳過去。

是這樣嗎?

Update 2:

我是很肯定原本忘了寫*this;沒錯

因為這是我很久以前寫的作業

最近抓出來看的時候才發現當時寫錯了XD

compile後還真的沒有糾正這種錯呢...

至於link error,有可能兩位大師說的沒錯吧

不過我是直接"編譯並執行"的,我記得好像DevC++會自動先存檔?

剛剛又重試了一次,還是一樣不行呢...

會出問題的應該就只有針對=的overloading的部分吧?

因為我只有改那裡啊@@

3 Answers

Rating
  • novus
    Lv 6
    1 decade ago
    Favorite Answer

    你先說說

    pass/return by reference 和 by valus之間的差異

    2009-02-17 21:24:48 補充:

    Q1

    cin、cout、cerr都是跨檔案的全域物件,也就是整個程式不管你開多少個檔案模組,用的都是同一個物件。

    如果你這樣寫

    ostream operator<<(ostream , const Array &);

    會在無意中幫輸入的ostream 複製、銷毀各兩次,但iostream禁止你破壞它的獨一性。

    事實上各種語言的 IO 或 File 物件都有複製的限制,因為多個物件存取同一個IO 或File Handle很容易破壞內部狀態一致性,常常造成恐怖的災難。

    Q2.沒規定一定要用const,只不過是為了模仿C++「自然」的operator行為罷了。

    會出錯是因你已經習慣const語意帶來的行為,所以在程式其他地方依賴這種行為而不自知。

    例如 a = b + c; 可以看作

    a.operater=( operator+(b, c) );

    operator=一定要接受const,型態才會符合 operator+ 回傳的暫時物件,因為暫時物件都帶有const屬性。

    又如 a = b = c; 可以看作

    a.operater=( b.operator=( c ) );

    請問如果 b.operator=() 若不 return* this,那麼a.operater=()要吃啥

    a = b; 之所以沒出錯,只不過是因為沒有人去使用 a.operator=( b ) 的傳回值

    在C++中「自然」的operator語意如

    T& T::operator=(const T&); //含+=、*=之類,要return by ref,且必return *this

    T T::operator+(const T&); //+-*/之類,要return by val

    T operator+(const T&, const T&);

    之所以說這是「自然」,是因為和內建的 int、char 的operator語意相同。如果你打算自己發明奇奇怪怪的用法,也沒人強迫你遵守,只是使用起來相當違反直覺罷了。

    至於link error沒看到程式碼很難說,不過我猜是你改完Header後沒有啟用重新編譯所有檔案,有些編譯器會偷懶用前一個版本的預編標頭。

    Q3.

    A& operator=(const A&);

    等號類的都必須return by ref,原因之一當然是為了模仿自然的operator行為。例如對int來說

    int a = 0;

    (a = 3)++;

    這段程式碼執行後 a 的值會變成4,這和return by ref的語意是相同的。

    但這種用途並畢竟不常見,如你提供的程式碼前面加const就已經避免這種情形發生,因此另一個目的就是為了效能。

    2009-02-18 21:22:20 補充:

    沒寫return確實是錯誤,編譯器沒找出來是編譯器失職

    除了int main編譯器會暗中補上return外,其他只要有寫return type就要手動return某些東西,就算是垃圾也好。

    不過return垃圾只要沒人用就不會怎樣

    存檔一萬遍也沒有用,他不會看你新改的header。大部分編譯器都會使用上次編譯的結果,只更新部分的.obj。

    而Dev C++在掃描更新的檔案時會有漏失,這是bug之一。所以要用「重新編譯全部檔案」而非「編譯」

    • Login to reply the answers
  • 1 decade ago

    你運氣不是好,是太好!

    這裡兩大高手幫你解惑!

    • Login to reply the answers
  • Lv 7
    1 decade ago

    小子,你運氣好.難得novus回應.要仔細聽.一字萬金啊.

    俺在此先開開路吧... :)

    你的第一題有一點迷糊,俺幫你講清楚一點.

    若把第一個&那掉也就是說用pass by value的方法回傳而不是用pass by reference的方法.

    第二題.照語法來講operator=()裡的參數用const或不用const都對.不過在用的時候就有關係了.比如說.

    HugeInt a;

    const HugeInt b;

    a = b; /* 你的operator=()裡的參數若不用const那就會出錯. */

    2009-02-17 08:27:41 補充:

    若你沒寫return *this.但你的回傳型態是HugeInt &的話那肯定在編譯時會出錯.

    第三題.照語法來講operator=()裡的參數用const &或不用const &都對.你在改過你的class之後有無存檔?

    • Login to reply the answers
Still have questions? Get your answers by asking now.