2012-01-11 38 views
2

我:C++鑄造導出到void *和恢復基礎

class A {...}; 

class B : public A {...}; 

class C : public B {...}; 

然後我存儲Ç實例爲void *:

C *instance = new C(); 
void *pC = instance; 

它是確定,使這個:

B *pB = reinterpret_cast<B*>(pC); 

或者我必須轉換成C * PS:我在我的程序中有更多從B派生出來的類,我不確定是否可以像我在做的那樣投擲(對B *)。

爲什麼無效*:我在box2d引擎中使用物理主體類的void *userdata' field。我不能有存儲我的課在其他方式

+0

'我不能以其他方式存儲我的課程。「 - 你確定嗎?通常,在C++中,將普通類轉換爲模板允許使用像'T * userData'而不是'void * userData'(其中'T'是實例化模板的類型。 – 2012-01-11 12:23:48

+0

@FrerichRaabe:我是使用將userData存儲爲void *的Box2D Phys引擎。我不認爲這是一個好主意,我自己修改Phys引擎的代碼 – Andrew 2012-01-11 12:31:03

回答

3

我建議鑄造回原來的C*然後做一個dynamic_castB*爲了遵循C++規則 - 儘管你應該避免在第一投射到void*放置並使用基址指針(A*)代替void ptr。

+0

我無法避免鑄造無效*,因爲我將我的類存儲爲void *另一個extern類的userdata字段 – Andrew 2012-01-11 12:15:53

+0

爲了公平起見, 'void *'指針可以是一個很好的類型擦除函數指針和函數模板的組合。雖然,你可能不會在用戶代碼中這樣做,而是在一個庫中。 – Xeo 2012-01-11 12:16:00

+2

這裏適當的強制轉換'C * - > B *'應該是'static_cast'。 'dynamic_cast'用於在繼承樹中向下投射。首先需要轉換爲'C *',否則代碼可能會因爲多重繼承而中斷。 – filmor 2012-01-11 12:18:07

0

這將工作正常。在這種情況下,您只能訪問方法AB。 (你會簡單地「隱藏」C的方法。)

-1

無效投射*總是一個壞主意,所以做一個dynamic_cast。如果你必須這樣做,它主要意味着你的代碼需要重新分解因爲它是一個對象設計缺陷。

1

對於您顯示的代碼,應該可以直接投射到B*,您可以使用static_cast來實現此目的。但是,通常,指向基類和派生類的指針可能不同,您必須先將其轉換爲原始類型,然後纔將其轉換爲指向base的指針。

編輯:在實踐中應該是單身繼承,但一般來說它是UB。

+1

你怎麼知道從'C *'到'B *'的轉換是無操作?我不相信這是任何地方的任務。 – 2012-01-11 12:35:43

+0

@KerrekSB:同意,即使對於標準佈局類,它似乎也沒有強制要求。我編輯了答案,使它更清楚地表明它是UB,即使它是通常如何實現的。 – 2012-01-11 13:33:23

+0

我會以另一種方式說「這是UB,但有時指向基地的指針與派生的指針相同,你可以用重新解釋演員逃脫」......儘管所有這些都發生在編譯時,所以我會說,如果正確的解決方案沒有問題,那麼推薦一些可能只是有時不會被破壞的建議是非常糟糕的建議。 – 2012-01-11 13:40:23

1

一般的規則是,當你從一個指針指向void *時,你應該總是回退到你最初來自的那個。

由於舊的APIs,鑄造成無效*有時是必要的惡魔。

有時它是通過設計完成創建一個「光」模板。輕型模板是您編寫處理指向對象指針集合的代碼的地方,這些指針都以相同的方式處理,並且這樣可以防止必須爲每種類型生成代碼。

圍繞這段代碼,你有一個強類型模板,它可以簡單地來回轉換(可能會被內聯),所以用戶可以得到強類型的代碼,但是實現不會太臃腫。