[英]C++ casting for C-style downcasting
當使用使用C樣式繼承(利用C結構的標准布局)的C API(例如GLib)時 ,我們通常使用C樣式強制轉換進行向下轉換:
struct base_object
{
int x;
int y;
int z;
};
struct derived_object
{
base_object base;
int foo;
int bar;
};
void func(base_object* b)
{
derived_object* d = (derived_object*) b; /* Downcast */
}
但是,如果我們正在編寫使用像這樣的C-API的新C ++代碼,是否應該繼續使用C樣式的強制轉換,還是應該選擇C ++強制轉換? 如果是后者,我們應該使用哪種類型的C ++強制轉換來模擬C向下轉換?
起初,我認為reinterpret_cast
將是合適的:
derived_object* d = reinterpret_cast<derived_object*>(b);
但是,我總是對reinterpret_cast
保持警惕,因為C ++標准幾乎不會保證會發生什么。 使用static_cast
來void*
可能更安全:
derived_object* d = static_cast<derived_object*>(static_cast<void*>(b))
當然,這確實很麻煩,讓我認為在這種情況下最好使用C樣式的強制轉換。
那么,這里的最佳實踐是什么?
像這樣使用C-API的新C ++代碼
不要以C風格編寫新的C ++代碼,它不會利用C ++語言功能,而且還會迫使包裝器用戶使用相同的“ C”風格。 而是創建一個適當的C ++類,該類包裝C API接口詳細信息並將其隱藏在C ++類后面。
我們應該繼續使用C樣式的強制類型轉換嗎
沒有
還是我們更喜歡C ++強制轉換
是的,但是只有在必須的時候。
使用C ++繼承和虛擬訪問器功能(可能)。 請說明您打算如何在func中使用派生對象,這可能為您提供更好的答案。
如果func希望使用派生對象的方法,則它應該接收派生對象。 如果它希望使用base_object的方法,但是由於指針指向了一個Applied_object,則方法有所改變,那么虛函數就是實現此目的的C ++方法。
另外,您想傳遞對func的引用,而不是指針。
dynamic_cast,需要滿足某些條件:
http://www.cplusplus.com/doc/tutorial/typecasting/
如果您只是將struct ptrs轉換為struct ptrs,並且知道自己想要什么,那么static_cast或reinterpret_cast可能是最好的?
但是,如果您真的對編寫C ++代碼感興趣,則強制轉換應該是您的最后也是最后的手段,因為有更好的模式。 我會考慮轉換的兩種常見情況是:
您正在與某種事件傳遞機制進行接口,該機制將通用基類傳遞給事件處理程序。
您有一個對象容器。 容器要求它包含同質類型(即,每個元素都包含相同的“事物”),但是您想在容器中存儲不同的類型。
但是,我總是對reinterpret_cast保持警惕,因為C ++標准幾乎不會保證會發生什么。
C ++樣式強制轉換與C樣式強制轉換一樣安全,因為C樣式強制轉換是根據C ++樣式強制轉換定義的。
5.4.4執行的轉換
— const_cast(5.2.11),
— static_cast(5.2.9),
—后面是const_cast的static_cast,
—一個reinterpret_cast(5.2.10),或
—一個reinterpret_cast,然后是const_cast,
可以使用顯式類型轉換的強制轉換符號執行。
[...]
如果可以用以上列出的一種以上的方法來解釋轉換,則使用列表中第一個出現的解釋,即使該解釋導致的轉換格式不正確。
可悲的答案是,您不能避免像編寫代碼那樣強制轉換代碼,因為編譯器對類之間的關系了解甚少。 您可能需要某種方式進行重構(廣播或類或使用它們的代碼)。
底線是:
如果可以,請使用適當的繼承。
如果不能,請使用reinterpret_cast。
如果您在C ++規范中查看C樣式轉換的規范,您會發現轉換符號是根據其他類型轉換運算符( dynamic_cast
, static_cast
, static_cast
, reinterpret_cast
, const_cast
)定義的,在這種情況下, reinterpret_cast
使用reinterpret_cast
。
另外,與您鏈接到的答案相比, reinterpret_cast
提供的保證更多。 您關心的是:
第9.2 / 20節:指向標准布局結構對象的指針(使用reinterpret_cast進行了適當轉換)指向其初始成員(或者,如果該成員是位字段,則指向其駐留的單元),反之亦然。
如果要使用強制轉換表示法,我認為最好顯式使用C ++類型轉換運算符。 但是,與其亂扔整個代碼,不如應該為每次轉換編寫一個函數(使用reinterpret_cast
實現),然后使用它。
derived_object *downcast_to_derived(base_object *b) {
return reinterpret_cast<derived_object*>(b);
}
我認為dynamic_cast
正是您想要的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.