2013-10-15 35 views
2

由於各種無聊的原因,我需要一個盒裝的int類,它主要充當一個int,但是它是一個從基礎繼承的類,所以它可以與對象層次結構的其他部分一起工作。我包含了一個構造函數,它接受一個int類型以及一個int類型轉換,這樣我就可以輕鬆地將我的盒裝int與代碼中的常量int進行混合。但是,我看到一個非常奇怪的行爲,我無法弄清楚:當我從函數返回盒裝int時,我希望它使用我的拷貝構造函數來引用另一個BoxedInt。然而,它將我的盒裝int轉換爲int,然後使用我的int構造函數。這會導致問題,因爲在我的實際代碼庫中,在這種情況下,我想要複製其他基類屬性,並且通過使用此構造函數路徑來丟失它們。這是有問題的代碼:爲什麼C++選擇將我的返回值轉換爲int?

class BoxedInt 
{ 
private: 
    int m_int; 
public: 
    BoxedInt():m_int(0) 
    { 
     trace(L"Constructed with nothing"); 
    } 

    BoxedInt(int val):m_int(val) 
    { 
     trace(L"Constructed with int"); 
    } 

    BoxedInt(BoxedInt& val) 
    { 
     trace(L"Constructed with reference"); 
     m_int = val.m_int; 
    } 

    operator int() 
    { 
     trace(L"Cast to int"); 
     return m_int; 
    } 
}; 

BoxedInt funky() 
{ 
    BoxedInt TempInt = 1; 
    return TempInt; 
} 

int main(int argc, char* argv[]) 
{ 
    trace(L"Start"); 
    BoxedInt test1 = 1; 
    trace(L"Copying"); 
    BoxedInt test2 = test1; 
    trace(L"Assigning from return value"); 
    BoxedInt test3 = funky(); 
    trace(L"Done"); 
    return 0; 
} 

當這個運行時,這裏的輸出:

Start 
Constructed with int 
Copying 
Constructed with reference 
Assigning from return value 
Constructed with int 
Constructed with reference 
Cast to int 
Constructed with int 
Done 

所以,當我分配一個值到另一個參考依據構造時,我會期望。但是,當我將函數的返回值賦給BoxedInt時,出於某種原因編譯器決定將其轉換爲int,然後使用int構造函數。我的C++很生疏,而且在編譯器這個奇怪的編譯器決策底部,我似乎無法抵消。有任何想法嗎?

+0

閱讀關於顯式關鍵字http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean – fasked

+0

編譯器不會**將返回值轉換爲' int',它**轉換**它。強制轉換是您在源代碼中編寫的內容,以告知編譯器進行轉換。同樣,'operator int'是一個**轉換操作符**,不是一個強制轉換。 –

回答

9

你的拷貝構造函數接受一個非const的引用,所以它不能與臨時調用 。 funky()的返回值是一個臨時值,因此複製構造函數不能用 來構造test3

使複製構造函數採取const引用,它應該 是好的。

+2

我覺得自己像一個白癡,我注意到,只要我發佈,但刪除已經太遲了!你們太快了。 –

+0

@Raja我不知道這是一個很好的網頁來引用。 Herb很好地解釋了這些問題,但他使用的例子是一種情況,你不應該使用引用來開始,const或其他;事實上他沒有提到這一點,可能會向很多讀者表明,這裏使用const引用是很好的編程實踐。 –

+0

好點詹姆斯。我刪除了該鏈接。 – Raja

5

您的複製構造函數需要一個非const引用,這意味着您不能將臨時參數綁定到參數,這正是您想要的返回方法所做的。因此,編譯器選擇其他路由。

改變你的拷貝構造:

BoxedInt(const BoxedInt &val) { 

事實上,鏘3.4 gives an error因爲BoxedInt test1 = 1;的。

+1

我認爲鏗鏘是對的。複製初始化需要可訪問的拷貝構造函數。而且我會解釋它的方式,這意味着一個可訪問的拷貝構造函數來複制至少在理論上構建的臨時文件。 –

+0

@JamesKanze,我完全同意。 – chris

+2

GCC 4.8.1也會在'BoxedInt test1 = 1;'中投訴,因爲它應該。 –

1

我相信這個問題(或其中一人)是拷貝構造函數簽名:

BoxedInt(BoxedInt& val) 

應該

BoxedInt(const BoxedInt& val) 
相關問題