2013-02-21 70 views
0

我有兩個具有類似結構的類。在C++中複製類似的類

class A{ 
    int a; 
    char *b; 
    float c; 
    A(char *str) { //allocate mem and assign to b } 
}; 

class B{ 
    int a; 
    char *b; 
    float c; 
    B(char *str) { //allocate mem and assign to b } 
    B(B & bref) { //properly copies all the data } 
}; 

我想的B的對象複製到的A的對象。以下轉換是否正確?

A aobj("aobjstr"); 
B bobj("bobjstr"); 
bobj = aobj; //case 1 
bobj = B(aobj); //case 2 

情況2會工作嗎?當B的拷貝構造函數被調用時,aobj會被正確轉換並解釋爲B &

編輯:那怎麼辦?

B bobj(aobj) 
+1

首先,這不是被調用的複製構造函數。您之前已經構建過它。其次,如果是的話,由於對非臨時性的非const引用,它會產生錯誤。 – chris 2013-02-21 07:15:11

+2

你試過了嗎?你很可能會得到錯誤,爲什麼你不從一個普通的類繼承? – 2013-02-21 07:15:17

+0

你已經知道C#或Java嗎?如果是這樣,那麼這可能會解釋這裏可能存在的誤解 - 特別是實際構造臨時對象的行'bobj = B(aobj)',將臨時對象拷貝(或試圖拷貝 - 不顯示賦值超載)從臨時對象到'bobj' ,然後丟棄臨時。原因基本上是'bobj'是實際的對象,而不是(像在Java中那樣)對對象的引用。 – Steve314 2013-02-21 07:22:26

回答

2

不,您不能在不編寫轉換構造函數或轉換運算符的情況下隱式轉換不相關的類型。據推測,你的編譯器告訴你這一點;雷給了錯誤,例如:

error: no match for ‘operator=’ in ‘bobj = aobj’ 
note: no known conversion for argument 1 from ‘A’ to ‘const B&’ 
error: no matching function for call to ‘B::B(A&)’ 

你可以允許通過給B轉換構造轉換:

class B { 
    // ... 
    B(A const & a) { /* properly copy the data */ } 
}; 

如果你不能改變的類,那麼你就需要一個非成員函數做轉換;但這可能只有在班級成員公開的情況下才有可能。在你的例子中,包括構造函數在內的所有成員都是私有的,所以這些類根本無法使用。據推測,你的真實代碼並非如此。

如果你想驚險的生活,你也許可以逃脫明確地重新詮釋一個A對象作爲B,因爲它們都是標準佈局類型使用相同的數據成員:

// DANGER: this will break if the layout of either class changes 
bobj = reinterpret_cast<B const &>(a); 

注因爲你的類分配內存,所以它可能需要在它的析構函數中釋放它;並且爲了避免雙重刪除,您還必須根據Rule of Three正確實現複製構造函數和複製賦值運算符。

如果這一切聽起來像太多的工作,爲什麼不使用std::string,爲您負責內存管理?

+0

謝謝!這非常精確。我很好奇你的陳述',因爲它們都是具有相同數據成員的標準佈局類型,reinterpret_cast可以工作'。我試圖尋找reinterpret_cast的文檔沒有找到確切的規範和工作。你能指點我一個詳細的文檔來源嗎? 順便說一句,我幾乎不知道類A和B的性質。它可能不包含浮動指針到其他對象。我把它包括在試圖掩蓋一切的一個最小的例子。 – krips89 2013-02-21 09:40:25

+0

@ krips89:在C++ 11標準中,'reinterpret_cast'在5.2.10中定義(特別是指針或標準佈局類型引用的第7和11章);標準佈局類在9/7中定義;和9.2/17中的佈局兼容類。但是最好不要使用它,因爲如果類佈局改變了,它可能會中斷,沒有錯誤或警告。 – 2013-02-21 10:24:42

0

您可以通過考慮以下事項做到這一點:

1)char* b使一個問題。當您將aobj複製到bobj時,指針aobj.b的值將被複制到bobj.b,這意味着它們都指向相同的內存位置並且像這樣更改:aobj.b[0] = 'Z'將導致bobj.b發生更改。

//... 
char b[MAXLEN]; 
//... 

更好的解決方案是,以限定一個構造(接受其它類型)和過載的分配(=)運算符:

可以通過從一個指針改變b到平面陣列解決這個,至少對於B類,並處理指針分配(爲新指針分配緩衝區並將內容複製到它)。

2)更新日期:樣本語法是這樣的:

bobj = B(reinterpret_cast<B&> (aobj)); 

    // or simply: 
    bobj = reinterpret_cast<B&> (aobj); 

3)注意,這是很危險的,不安全的,不推薦。這意味着您的解決方案的設計應該可能會改變。例如,A和B都可以從一個公共基類繼承; B繼承自A;或者B明確地定義了A類的構造函數和賦值運算符。這些更加推薦。

2

如果你試圖編譯它,你會發現這些都不起作用。首先你的構造函數是private

bobj = aobj; //case 1 

這試圖調用一個賦值運算符與簽名:

B& B::operator =(A const&) 

這不存在,編譯失敗。

bobj = B(aobj); //case 2 

這試圖調用A::operator B(),它不存在,編譯將失敗。

最後:

B bobj(aobj) 

這試圖調用與簽名B::B(A const&),它不存在,編譯失敗的構造函數。

你說,

我不能改變/修改A類和B,這些都是產生。

然後無論是生成器需要修復,或者你將不得不編寫自己的適配器。